Ejemplo n.º 1
0
        public void Create_TransferSyntaxExplicitLEBitsAllocatedGreaterThan16_ReturnsOtherWordPixelDataObject()
        {
            var dataset = new DicomDataset(DicomTransferSyntax.ExplicitVRLittleEndian);

            dataset.Add(DicomTag.BitsAllocated, (ushort)32);
            var pixelData = DicomPixelData.Create(dataset, true);

            Assert.Equal("OtherWordPixelData", pixelData.GetType().Name);
        }
Ejemplo n.º 2
0
        public void Create_TransferSyntaxExplicitLEBitsAllocatedLessThanOrEqualTo8_ReturnsOtherBytePixelDataObject(ushort bitsAllocated)
        {
            var dataset = new DicomDataset(DicomTransferSyntax.ExplicitVRLittleEndian);

            dataset.Add(DicomTag.BitsAllocated, bitsAllocated);
            var pixelData = DicomPixelData.Create(dataset, true);

            Assert.Equal("OtherBytePixelData", pixelData.GetType().Name);
        }
Ejemplo n.º 3
0
        public void Create_TransferSyntaxExplicitLEBitsAllocatedGreaterThan16_Throws()
        {
            var dataset = new DicomDataset(DicomTransferSyntax.ExplicitVRLittleEndian);

            dataset.Add(DicomTag.BitsAllocated, (ushort)17);
            var exception = Record.Exception(() => DicomPixelData.Create(dataset, true));

            Assert.NotNull(exception);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Loads the pixel data for specified frame and set the internal dataset
        ///
        /// </summary>
        /// <param name="dataset">dataset to load pixeldata from</param>
        /// <param name="frame">The frame number to create pixeldata for</param>
        private void Load(DicomDataset dataset, int frame)
        {
            Dataset = dataset;

            if (PixelData == null)
            {
                PixelData = DicomPixelData.Create(Dataset);
                PhotometricInterpretation = PixelData.PhotometricInterpretation;
            }

            if (Dataset.InternalTransferSyntax.IsEncapsulated)
            {
                // decompress single frame from source dataset
                DicomCodecParams cparams = null;
                if (Dataset.InternalTransferSyntax == DicomTransferSyntax.JPEGProcess1 || Dataset.InternalTransferSyntax == DicomTransferSyntax.JPEGProcess2_4)
                {
                    cparams = new DicomJpegParams {
                        ConvertColorspaceToRGB = true
                    };
                }

                var transcoder = new DicomTranscoder(Dataset.InternalTransferSyntax, DicomTransferSyntax.ExplicitVRLittleEndian);
                transcoder.InputCodecParams  = cparams;
                transcoder.OutputCodecParams = cparams;
                var buffer = transcoder.DecodeFrame(Dataset, frame);

                // clone the dataset because modifying the pixel data modifies the dataset
                var clone = Dataset.Clone();
                clone.InternalTransferSyntax = DicomTransferSyntax.ExplicitVRLittleEndian;

                var pixelData = DicomPixelData.Create(clone, true);
                pixelData.AddFrame(buffer);

                // temporary fix for JPEG compressed YBR images
                if ((Dataset.InternalTransferSyntax == DicomTransferSyntax.JPEGProcess1 || Dataset.InternalTransferSyntax == DicomTransferSyntax.JPEGProcess2_4) && pixelData.SamplesPerPixel == 3)
                {
                    pixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb;
                }

                _pixelData = PixelDataFactory.Create(pixelData, 0);
            }
            else
            {
                // pull uncompressed frame from source pixel data
                _pixelData = PixelDataFactory.Create(PixelData, frame);
            }

            _pixelData.Rescale(_scale);

            _overlays = DicomOverlayData.FromDataset(Dataset).Where(x => x.Type == DicomOverlayType.Graphics && x.Data != null).ToArray();

            _currentFrame = frame;

            CreatePipeline();
        }
Ejemplo n.º 5
0
        public void BitsStored_Setter_GreaterThanBitsAllocatedIsNotAllowed(ushort bitsAllocated, ushort bitsStored)
        {
            var dataset = new DicomDataset(DicomTransferSyntax.ExplicitVRLittleEndian);

            dataset.Add(DicomTag.BitsAllocated, bitsAllocated);
            var pixelData = DicomPixelData.Create(dataset, true);

            var exception = Record.Exception(() => pixelData.BitsStored = bitsStored);

            Assert.NotNull(exception);
        }
Ejemplo n.º 6
0
        /// <summary>Creates DICOM image object from dataset</summary>
        /// <param name="dataset">Source dataset</param>
        /// <param name="frame">Zero indexed frame number. If <paramref name="frame"/> is set to a negative number, the
        /// <see cref="DicomImage"/> object will remain in a partly initialized state, allowing for <see cref="WindowCenter"/>,
        /// <see cref="WindowWidth"/> and <see cref="GrayscaleColorMap"/> to be configured prior to rendering the image frames.</param>
        public DicomImage(DicomDataset dataset, int frame = 0)
        {
            ShowOverlays = true;

            _scale        = 1.0;
            _rerender     = true;
            _frameIndices = new ConcurrentDictionary <int, int>();

            _dataset     = DicomTranscoder.ExtractOverlays(dataset);
            _pixelData   = CreateDicomPixelData(_dataset);
            CurrentFrame = frame;
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Loads the pixel data for specified frame and set the internal dataset
        ///
        /// </summary>
        /// <param name="dataset">dataset to load pixeldata from</param>
        /// <param name="frame">The frame number to create pixeldata for</param>
        private void Load(DicomDataset dataset, int frame)
        {
            Dataset = DicomTranscoder.ExtractOverlays(dataset);

            if (PixelData == null)
            {
                PixelData = DicomPixelData.Create(Dataset);
                PhotometricInterpretation = PixelData.PhotometricInterpretation;
            }
            if (frame < 0)
            {
                CurrentFrame = frame;
                return;
            }

            if (Dataset.InternalTransferSyntax.IsEncapsulated)
            {
                // decompress single frame from source dataset
                var transcoder = new DicomTranscoder(
                    this.Dataset.InternalTransferSyntax,
                    DicomTransferSyntax.ExplicitVRLittleEndian);
                var buffer = transcoder.DecodeFrame(Dataset, frame);

                // clone the dataset because modifying the pixel data modifies the dataset
                var clone = Dataset.Clone();
                clone.InternalTransferSyntax = DicomTransferSyntax.ExplicitVRLittleEndian;

                var pixelData = DicomPixelData.Create(clone, true);
                TrimDecodedPixelDataProperties(pixelData, Dataset.InternalTransferSyntax);
                pixelData.AddFrame(buffer);

                _pixelData = PixelDataFactory.Create(pixelData, 0);
            }
            else
            {
                // pull uncompressed frame from source pixel data
                _pixelData = PixelDataFactory.Create(PixelData, frame);
            }

            _pixelData = _pixelData.Rescale(_scale);

            _overlays =
                DicomOverlayData.FromDataset(Dataset)
                .Where(x => x.Type == DicomOverlayType.Graphics && x.Data != null)
                .ToArray();

            CurrentFrame = frame;

            if (_pipeline == null)
            {
                CreatePipeline();
            }
        }
Ejemplo n.º 8
0
        public void HighBit_Setter_SmallerThanBitsAllocatedIsAllowed(ushort bitsAllocated, ushort highBit)
        {
            var dataset = new DicomDataset(DicomTransferSyntax.ExplicitVRLittleEndian);

            dataset.Add(DicomTag.BitsAllocated, bitsAllocated);
            var pixelData = DicomPixelData.Create(dataset, true);

            var exception = Record.Exception(() => pixelData.HighBit = highBit);

            Assert.Null(exception);
            Assert.Equal(highBit, pixelData.HighBit);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Create <see cref="GrayscaleRenderOptions"/>  from <paramref name="dataset"/> and populate the options properties with values:
        /// Bit Depth
        /// Rescale Slope
        /// Rescale Intercept
        /// Window Width
        /// Window Center
        /// </summary>
        /// <param name="dataset">Dataset to extract <see cref="GrayscaleRenderOptions"/> from</param>
        /// <returns>New grayscale render options instance</returns>
        public static GrayscaleRenderOptions FromDataset(DicomDataset dataset)
        {
            var bits    = BitDepth.FromDataset(dataset);
            var options = new GrayscaleRenderOptions(bits);

            options.RescaleSlope     = dataset.Get <double>(DicomTag.RescaleSlope, 1.0);
            options.RescaleIntercept = dataset.Get <double>(DicomTag.RescaleIntercept, 0.0);

            if (dataset.Contains(DicomTag.WindowWidth) && dataset.Get <double>(DicomTag.WindowWidth) != 0.0)
            {
                //If dataset contains WindowWidth and WindowCenter valid attributes used initially for the grayscale options
                options.WindowWidth  = dataset.Get <double>(DicomTag.WindowWidth);
                options.WindowCenter = dataset.Get <double>(DicomTag.WindowCenter);
            }
            else if (dataset.Contains(DicomTag.SmallestImagePixelValue) && dataset.Contains(DicomTag.LargestImagePixelValue))
            {
                //If dataset contains valid SmallesImagePixelValue and LargesImagePixelValue attributes, use range to calculage
                //WindowWidth and WindowCenter
                int smallValue = dataset.Get <int>(DicomTag.SmallestImagePixelValue, 0);
                int largeValue = dataset.Get <int>(DicomTag.LargestImagePixelValue, 0);

                largeValue = (int)((largeValue * options.RescaleSlope) + options.RescaleIntercept);
                smallValue = (int)((smallValue * options.RescaleSlope) + options.RescaleIntercept);

                if (smallValue != 0 || largeValue != 0)
                {
                    options.WindowWidth  = Math.Abs(largeValue - smallValue);
                    options.WindowCenter = (largeValue + smallValue) / 2.0;
                }
            }
            else
            {
                //If reached here, minimum and maximum pixel values calculated from pixels data to calculate
                //WindowWidth and WindowCenter
                int padding = dataset.Get <int>(DicomTag.PixelPaddingValue, 0, bits.MinimumValue);

                var pixelData = DicomPixelData.Create(dataset);
                var pixels    = PixelDataFactory.Create(pixelData, 0);
                var range     = pixels.GetMinMax(padding);

                range.Maximum = (int)((range.Maximum * options.RescaleSlope) + options.RescaleIntercept);
                range.Minimum = (int)((range.Minimum * options.RescaleSlope) + options.RescaleIntercept);

                options.WindowWidth  = Math.Abs(range.Maximum - range.Minimum);
                options.WindowCenter = (range.Maximum + range.Minimum) / 2.0;
            }

            options.VOILUTFunction = dataset.Get <string>(DicomTag.VOILUTFunction, "LINEAR");
            options.Monochrome1    = dataset.Get <PhotometricInterpretation>(DicomTag.PhotometricInterpretation) == PhotometricInterpretation.Monochrome1;

            return(options);
        }
Ejemplo n.º 10
0
        private void Load(DicomDataset dataset)
        {
            Dataset = dataset;
            if (Dataset.InternalTransferSyntax.IsEncapsulated)
            {
                Dataset = Dataset.ChangeTransferSyntax(DicomTransferSyntax.ExplicitVRLittleEndian, null);
            }

            DicomPixelData pixelData = DicomPixelData.Create(Dataset);

            _pixelData = PixelDataFactory.Create(pixelData, 0);
            _overlays  = DicomOverlayData.FromDataset(Dataset);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Create pixel data object based on <paramref name="dataset"/>.
        /// </summary>
        /// <param name="dataset">Dataset containing pixel data.</param>
        /// <returns>For non-encapsulated dataset, create pixel data object from original pixel data. For encapsulated dataset,
        /// create "empty" pixel data object to subsequentially be filled with uncompressed data for each frame.</returns>
        private static DicomPixelData CreateDicomPixelData(DicomDataset dataset)
        {
            var inputTransferSyntax = dataset.InternalTransferSyntax;

            if (!inputTransferSyntax.IsEncapsulated)
            {
                return(DicomPixelData.Create(dataset));
            }

            // Clone the encapsulated dataset because modifying the pixel data modifies the dataset
            var clone = dataset.Clone();

            clone.InternalTransferSyntax = DicomTransferSyntax.ExplicitVRLittleEndian;

            var pixelData = DicomPixelData.Create(clone, true);

            // temporary fix for JPEG compressed YBR images, according to enforcement above
            if ((inputTransferSyntax == DicomTransferSyntax.JPEGProcess1 ||
                 inputTransferSyntax == DicomTransferSyntax.JPEGProcess2_4) && pixelData.SamplesPerPixel == 3)
            {
                // When converting to RGB in Dicom.Imaging.Codec.Jpeg.i, PlanarConfiguration is set to Interleaved
                pixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb;
                pixelData.PlanarConfiguration       = PlanarConfiguration.Interleaved;
            }

            // temporary fix for JPEG 2000 Lossy images
            if ((inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossy &&
                 pixelData.PhotometricInterpretation == PhotometricInterpretation.YbrIct) ||
                (inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossless &&
                 pixelData.PhotometricInterpretation == PhotometricInterpretation.YbrRct))
            {
                // Converted to RGB in Dicom.Imaging.Codec.Jpeg2000.cpp
                pixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb;
            }

            // temporary fix for JPEG2000 compressed YBR images
            if ((inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossless ||
                 inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossy) &&
                (pixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull ||
                 pixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422 ||
                 pixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial422))
            {
                // For JPEG2000 YBR type images in Dicom.Imaging.Codec.Jpeg2000.cpp,
                // YBR_FULL is applied and PlanarConfiguration is set to Planar
                pixelData.PhotometricInterpretation = PhotometricInterpretation.YbrFull;
                pixelData.PlanarConfiguration       = PlanarConfiguration.Planar;
            }

            return(pixelData);
        }
Ejemplo n.º 12
0
        private static void TrimDecodedPixelDataProperties(
            DicomPixelData decodedPixelData,
            DicomTransferSyntax inputTransferSyntax)
        {
            if (!inputTransferSyntax.IsEncapsulated)
            {
                return;
            }

            // temporary fix for JPEG compressed YBR images, according to enforcement above
            if ((inputTransferSyntax == DicomTransferSyntax.JPEGProcess1 ||
                 inputTransferSyntax == DicomTransferSyntax.JPEGProcess2_4) && decodedPixelData.SamplesPerPixel == 3)
            {
                // When converting to RGB in Dicom.Imaging.Codec.Jpeg.i, PlanarConfiguration is set to Interleaved
                decodedPixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb;
                decodedPixelData.PlanarConfiguration       = PlanarConfiguration.Interleaved;
            }

            // temporary fix for JPEG 2000 Lossy images
            if ((inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossy &&
                 decodedPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrIct) ||
                (inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossless &&
                 decodedPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrRct))
            {
                // Converted to RGB in Dicom.Imaging.Codec.Jpeg2000.cpp
                decodedPixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb;
            }

            // temporary fix for JPEG lossless and JPEG2000 compressed YBR images
            if ((inputTransferSyntax == DicomTransferSyntax.JPEGProcess14 ||
                 inputTransferSyntax == DicomTransferSyntax.JPEGProcess14SV1 ||
                 inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossless ||
                 inputTransferSyntax == DicomTransferSyntax.JPEG2000Lossy) &&
                (decodedPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull ||
                 decodedPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422 ||
                 decodedPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial422))
            {
                // For JPEG lossless YBR type images in Dicom.Imaging.Codec.Jpeg.i and JPEG2000 YBR type images in Dicom.Imaging.Codec.Jpeg2000.cpp,
                // YBR_FULL is applied and PlanarConfiguration is set to Planar
                decodedPixelData.PhotometricInterpretation = PhotometricInterpretation.YbrFull;
                decodedPixelData.PlanarConfiguration       = PlanarConfiguration.Planar;
            }
        }
Ejemplo n.º 13
0
        private IByteBuffer Load()
        {
            var tag = OverlayTag(DicomTag.OverlayData);

            if (Dataset.Contains(tag))
            {
                var elem = Dataset.FirstOrDefault(x => x.Tag == tag) as DicomElement;
                return(elem.Buffer);
            }
            else
            {
                // overlay embedded in high bits of pixel data
                if (Dataset.InternalTransferSyntax.IsEncapsulated)
                {
                    throw new DicomImagingException(
                              "Attempted to extract embedded overlay from compressed pixel data. Decompress pixel data before attempting this operation.");
                }

                var pixels = DicomPixelData.Create(Dataset);

                // (1,1) indicates top left pixel of image
                int ox = Math.Max(0, OriginX - 1);
                int oy = Math.Max(0, OriginY - 1);
                int ow = Columns;
                int oh = Rows;

                var frame = pixels.GetFrame(0);

                var bits = new BitList();
                bits.Capacity = Rows * Columns;
                int mask = 1 << BitPosition;

                // Sanity check: do not collect overlay data if Overlay Bit Position is within the used pixel range. (#110)
                if (this.BitPosition <= pixels.HighBit && this.BitPosition > pixels.HighBit - pixels.BitsStored)
                {
                    // Do nothing
                }
                else if (pixels.BitsAllocated == 8)
                {
                    var data = IO.ByteConverter.ToArray <byte>(frame);

                    for (int y = 0; y < oh; y++)
                    {
                        int n = (y + oy) * pixels.Width + ox;
                        int i = y * Columns;
                        for (int x = 0; x < ow; x++)
                        {
                            if ((data[n] & mask) != 0)
                            {
                                bits[i] = true;
                            }
                            n++;
                            i++;
                        }
                    }
                }
                else if (pixels.BitsAllocated == 16)
                {
                    // we don't really care if the pixel data is signed or not
                    var data = IO.ByteConverter.ToArray <ushort>(frame);

                    for (int y = 0; y < oh; y++)
                    {
                        int n = (y + oy) * pixels.Width + ox;
                        int i = y * Columns;
                        for (int x = 0; x < ow; x++)
                        {
                            if ((data[n] & mask) != 0)
                            {
                                bits[i] = true;
                            }
                            n++;
                            i++;
                        }
                    }
                }
                else
                {
                    throw new DicomImagingException(
                              "Unable to extract embedded overlay from pixel data with bits stored greater than 16.");
                }

                return(new MemoryByteBuffer(bits.Array));
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Create image rendering pipeline according to the <see cref="DicomPixelData.PhotometricInterpretation">photometric interpretation</see>
        /// of the pixel data.
        /// </summary>
        private static PipelineData CreatePipelineData(DicomDataset dataset, DicomPixelData pixelData)
        {
            var pi      = pixelData.PhotometricInterpretation;
            var samples = dataset.GetSingleValueOrDefault(DicomTag.SamplesPerPixel, (ushort)0);

            // temporary fix for JPEG compressed YBR images
            if ((dataset.InternalTransferSyntax == DicomTransferSyntax.JPEGProcess1 ||
                 dataset.InternalTransferSyntax == DicomTransferSyntax.JPEGProcess2_4) && samples == 3)
            {
                pi = PhotometricInterpretation.Rgb;
            }

            // temporary fix for JPEG 2000 Lossy images
            if (pi == PhotometricInterpretation.YbrIct || pi == PhotometricInterpretation.YbrRct)
            {
                pi = PhotometricInterpretation.Rgb;
            }

            if (pi == null)
            {
                // generally ACR-NEMA
                if (samples == 0 || samples == 1)
                {
                    pi = dataset.Contains(DicomTag.RedPaletteColorLookupTableData)
                        ? PhotometricInterpretation.PaletteColor
                        : PhotometricInterpretation.Monochrome2;
                }
                else
                {
                    // assume, probably incorrectly, that the image is RGB
                    pi = PhotometricInterpretation.Rgb;
                }
            }

            IPipeline pipeline;
            GrayscaleRenderOptions renderOptions = null;

            if (pi == PhotometricInterpretation.Monochrome1 || pi == PhotometricInterpretation.Monochrome2)
            {
                //Monochrome1 or Monochrome2 for grayscale image
                renderOptions = GrayscaleRenderOptions.FromDataset(dataset);
                pipeline      = new GenericGrayscalePipeline(renderOptions);
            }
            else if (pi == PhotometricInterpretation.Rgb || pi == PhotometricInterpretation.YbrFull ||
                     pi == PhotometricInterpretation.YbrFull422 || pi == PhotometricInterpretation.YbrPartial422)
            {
                //RGB for color image
                pipeline = new RgbColorPipeline();
            }
            else if (pi == PhotometricInterpretation.PaletteColor)
            {
                //PALETTE COLOR for Palette image
                pipeline = new PaletteColorPipeline(pixelData);
            }
            else
            {
                throw new DicomImagingException("Unsupported pipeline photometric interpretation: {0}", pi);
            }

            return(new PipelineData {
                Pipeline = pipeline, RenderOptions = renderOptions
            });
        }
Ejemplo n.º 15
0
        private void Load(DicomDataset ds)
        {
            _rows    = ds.Get <ushort>(OverlayTag(DicomTag.OverlayRows));
            _columns = ds.Get <ushort>(OverlayTag(DicomTag.OverlayColumns));

            var type = ds.Get <string>(OverlayTag(DicomTag.OverlayType), "Unknown");

            if (type.StartsWith("R"))
            {
                _type = DicomOverlayType.ROI;
            }
            else
            {
                _type = DicomOverlayType.Graphics;
            }

            DicomTag tag = OverlayTag(DicomTag.OverlayOrigin);

            if (ds.Contains(tag))
            {
                _originX = ds.Get <short>(tag, 0, 1);
                _originY = ds.Get <short>(tag, 1, 1);
            }

            _bitsAllocated = ds.Get <ushort>(OverlayTag(DicomTag.OverlayBitsAllocated), 0, 1);
            _bitPosition   = ds.Get <ushort>(OverlayTag(DicomTag.OverlayBitPosition), 0, 0);

            tag = OverlayTag(DicomTag.OverlayData);
            if (ds.Contains(tag))
            {
                var elem = ds.FirstOrDefault(x => x.Tag == tag) as DicomElement;
                _data = elem.Buffer;
            }
            else
            {
                // overlay embedded in high bits of pixel data
                if (ds.InternalTransferSyntax.IsEncapsulated)
                {
                    throw new DicomImagingException("Attempted to extract embedded overlay from compressed pixel data. Decompress pixel data before attempting this operation.");
                }

                var pixels = DicomPixelData.Create(ds);

                // (1,1) indicates top left pixel of image
                int ox = Math.Max(0, _originX - 1);
                int oy = Math.Max(0, _originY - 1);
                int ow = _rows - (pixels.Width - _rows - ox);
                int oh = _columns - (pixels.Height - _columns - oy);

                var frame = pixels.GetFrame(0);

                // calculate length of output buffer
                var count = (_rows * _columns) / 8;
                if (((_rows * _columns) % 8) != 0)
                {
                    count++;
                }
                if ((count & 1) != 0)
                {
                    count++;
                }

                var bytes = new byte[count];
                var bits  = new BitArray(bytes);
                int mask  = 1 << _bitPosition;

                if (pixels.BitsAllocated == 8)
                {
                    var data = ByteBufferEnumerator <byte> .Create(frame).ToArray();

                    for (int y = oy; y < oh; y++)
                    {
                        int n = (y * pixels.Width) + ox;
                        int i = (y - oy) * _columns;
                        for (int x = ox; x < ow; x++)
                        {
                            if ((data[n] & mask) != 0)
                            {
                                bits[i] = true;
                            }
                            n++;
                            i++;
                        }
                    }
                }
                else if (pixels.BitsAllocated == 16)
                {
                    // we don't really care if the pixel data is signed or not
                    var data = ByteBufferEnumerator <ushort> .Create(frame).ToArray();

                    for (int y = oy; y < oh; y++)
                    {
                        int n = (y * pixels.Width) + ox;
                        int i = (y - oy) * _columns;
                        for (int x = ox; x < ow; x++)
                        {
                            if ((data[n] & mask) != 0)
                            {
                                bits[i] = true;
                            }
                            n++;
                            i++;
                        }
                    }
                }
                else
                {
                    throw new DicomImagingException("Unable to extract embedded overlay from pixel data with bits stored greater than 16.");
                }

                _data = new MemoryByteBuffer(bytes);
            }

            _description = ds.Get <string>(OverlayTag(DicomTag.OverlayDescription), String.Empty);
            _subtype     = ds.Get <string>(OverlayTag(DicomTag.OverlaySubtype), String.Empty);
            _label       = ds.Get <string>(OverlayTag(DicomTag.OverlayLabel), String.Empty);

            _frames      = ds.Get <int>(OverlayTag(DicomTag.NumberOfFramesInOverlay), 0, 1);
            _frameOrigin = ds.Get <ushort>(OverlayTag(DicomTag.ImageFrameOrigin), 0, 1);

            //TODO: include ROI
        }
Ejemplo n.º 16
0
        internal static void Decode(
            DicomPixelData oldPixelData,
            DicomPixelData newPixelData,
            DicomJpeg2000Params parameters)
        {
            var pixelCount = oldPixelData.Height * oldPixelData.Width;

            if (newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrIct
                || newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrRct)
            {
                newPixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb;
            }

            if (newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422
                || newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial422)
            {
                newPixelData.PhotometricInterpretation = PhotometricInterpretation.YbrFull;
            }

            if (newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull)
            {
                newPixelData.PlanarConfiguration = PlanarConfiguration.Planar;
            }

            for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++)
            {
                var jpegData = oldPixelData.GetFrame(frame);

                // Destination frame should be of even length
                var frameSize = newPixelData.UncompressedFrameSize;
                if ((frameSize & 1) == 1) ++frameSize;
                var destArray = new byte[frameSize];

                var image = J2kImage.FromBytes(jpegData.Data, ToParameterList(parameters, true));

                if (image == null) throw new InvalidOperationException("Error in JPEG 2000 code stream!");

                for (var c = 0; c < image.NumberOfComponents; c++)
                {
                    var comp = image.GetComponent(c);

                    var pos = newPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? (c * pixelCount) : c;
                    var offset = newPixelData.PlanarConfiguration == PlanarConfiguration.Planar
                                     ? 1
                                     : image.NumberOfComponents;

                    if (newPixelData.BytesAllocated == 1)
                    {
                        for (var p = 0; p < pixelCount; p++)
                        {
                            destArray[pos] = comp[p];
                            pos += offset;
                        }
                    }
#if SUPPORT16BIT
                    else if (newPixelData.BytesAllocated == 2)
                    {
                        for (var p = 0; p < pixelCount; p++)
                        {
                            destArray[2 * pos] = comp[p];
                            pos += offset;
                        }
                    }
#endif
                    else
                    {
                        throw new InvalidOperationException(
                            $"JPEG 2000 codec does not support Bits Allocated == {newPixelData.BitsAllocated}!");
                    }
                }

                newPixelData.AddFrame(new MemoryByteBuffer(destArray));
            }
        }
Ejemplo n.º 17
0
        internal static void Encode(
            DicomPixelData oldPixelData,
            DicomPixelData newPixelData,
            DicomJpeg2000Params parameters)
        {
            if ((oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422)
                || (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial422)
                || (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial420))
            {
                throw new InvalidOperationException(
                    "Photometric Interpretation '" + oldPixelData.PhotometricInterpretation
                    + "' not supported by JPEG 2000 encoder");
            }

            var jparams = parameters ?? new DicomJpeg2000Params();

            jparams.Irreversible = newPixelData.IsLossy;
            jparams.AllowMCT = oldPixelData.PhotometricInterpretation == PhotometricInterpretation.Rgb;

            var pixelCount = oldPixelData.Height * oldPixelData.Width;

            for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++)
            {
                var frameData = oldPixelData.GetFrame(frame);

                var nc = oldPixelData.SamplesPerPixel;
                var sgnd = oldPixelData.PixelRepresentation == PixelRepresentation.Signed
                           && !jparams.EncodeSignedPixelValuesAsUnsigned;
                var comps = new int[nc][];

                var colorSpace = GetJpegColorSpace(oldPixelData.PhotometricInterpretation);

                for (var c = 0; c < nc; c++)
                {
                    var comp = new int[pixelCount];

                    var pos = oldPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? (c * pixelCount) : c;
                    var offset = oldPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? 1 : nc;

                    if (oldPixelData.BytesAllocated == 1)
                    {
                        var data = frameData.Data;
                        if (sgnd)
                        {
                            if (oldPixelData.BitsStored < 8)
                            {
                                var sign = (byte)(1 << oldPixelData.HighBit);
                                var mask = (byte)(0xff >> (oldPixelData.BitsAllocated - oldPixelData.BitsStored));
                                for (var p = 0; p < pixelCount; p++)
                                {
                                    var pixel = (sbyte)data[pos];
                                    comp[p] = (pixel & sign) > 0 ? -(((-pixel) & mask) + 1) : pixel;
                                    pos += offset;
                                }
                            }
                            else
                            {
                                for (var p = 0; p < pixelCount; p++)
                                {
                                    comp[p] = (sbyte)data[pos];
                                    pos += offset;
                                }
                            }
                        }
                        else
                        {
                            for (var p = 0; p < pixelCount; p++)
                            {
                                comp[p] = data[pos];
                                pos += offset;
                            }
                        }
                    }
#if SUPPORT16BIT
                    else if (oldPixelData.BytesAllocated == 2)
                    {
                        if (sgnd)
                        {
                            if (oldPixelData.BitsStored < 16)
                            {
                                var frameData16 = new ushort[pixelCount];
                                Buffer.BlockCopy(frameData.Data, 0, frameData16, 0, (int)frameData.Size);

                                var sign = (ushort)(1 << oldPixelData.HighBit);
                                var mask = (ushort)(0xffff >> (oldPixelData.BitsAllocated - oldPixelData.BitsStored));
                                for (var p = 0; p < pixelCount; p++)
                                {
                                    var pixel = frameData16[pos];
                                    comp[p] = (pixel & sign) > 0 ? -(((-pixel) & mask) + 1) : pixel;
                                    pos += offset;
                                }
                            }
                            else
                            {
                                var frameData16 = new short[pixelCount];
                                Buffer.BlockCopy(frameData.Data, 0, frameData16, 0, (int)frameData.Size);

                                for (var p = 0; p < pixelCount; p++)
                                {
                                    comp[p] = frameData16[pos];
                                    pos += offset;
                                }
                            }
                        }
                        else
                        {
                            var frameData16 = new ushort[pixelCount];
                            Buffer.BlockCopy(frameData.Data, 0, frameData16, 0, (int)frameData.Size);

                            for (var p = 0; p < pixelCount; p++)
                            {
                                comp[p] = frameData16[pos];
                                pos += offset;
                            }
                        }
                    }
#endif
                    else
                    {
                        throw new InvalidOperationException(
                            $"JPEG 2000 codec does not support Bits Allocated == {oldPixelData.BitsAllocated}");
                    }

                    comps[c] = comp;
                }

                var image = new PortableImageSource(
                    oldPixelData.Width,
                    oldPixelData.Height,
                    nc,
                    oldPixelData.BitsAllocated,
                    Enumerable.Repeat(sgnd, nc).ToArray(),
                    comps);

                try
                {
                    var cbuf = J2kImage.ToBytes(image, ToParameterList(jparams, false));
                    newPixelData.AddFrame(new MemoryByteBuffer(cbuf));
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException("Unable to JPEG 2000 encode image", e);
                }
            }

            if (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.Rgb)
            {
                newPixelData.PlanarConfiguration = PlanarConfiguration.Interleaved;

                if (jparams.AllowMCT && jparams.UpdatePhotometricInterpretation)
                {
                    if (newPixelData.IsLossy && jparams.Irreversible) newPixelData.PhotometricInterpretation = PhotometricInterpretation.YbrIct;
                    else newPixelData.PhotometricInterpretation = PhotometricInterpretation.YbrRct;
                }
            }
        }
Ejemplo n.º 18
0
        private IByteBuffer Load()
        {
            var tag = OverlayTag(DicomTag.OverlayData);

            if (Dataset.Contains(tag))
            {
                var elem = Dataset.FirstOrDefault(x => x.Tag == tag) as DicomElement;
                return(elem.Buffer);
            }
            else
            {
                // overlay embedded in high bits of pixel data
                if (Dataset.InternalTransferSyntax.IsEncapsulated)
                {
                    throw new DicomImagingException("Attempted to extract embedded overlay from compressed pixel data. Decompress pixel data before attempting this operation.");
                }

                var pixels = DicomPixelData.Create(Dataset);

                // (1,1) indicates top left pixel of image
                int ox = Math.Max(0, OriginX - 1);
                int oy = Math.Max(0, OriginY - 1);
                int ow = Rows - (pixels.Width - Rows - ox);
                int oh = Columns - (pixels.Height - Columns - oy);

                var frame = pixels.GetFrame(0);

                var bits = new BitList();
                bits.Capacity = Rows * Columns;
                int mask = 1 << BitPosition;

                if (pixels.BitsAllocated == 8)
                {
                    var data = ByteBufferEnumerator <byte> .Create(frame).ToArray();

                    for (int y = oy; y < oh; y++)
                    {
                        int n = (y * pixels.Width) + ox;
                        int i = (y - oy) * Columns;
                        for (int x = ox; x < ow; x++)
                        {
                            if ((data[n] & mask) != 0)
                            {
                                bits[i] = true;
                            }
                            n++;
                            i++;
                        }
                    }
                }
                else if (pixels.BitsAllocated == 16)
                {
                    // we don't really care if the pixel data is signed or not
                    var data = ByteBufferEnumerator <ushort> .Create(frame).ToArray();

                    for (int y = oy; y < oh; y++)
                    {
                        int n = (y * pixels.Width) + ox;
                        int i = (y - oy) * Columns;
                        for (int x = ox; x < ow; x++)
                        {
                            if ((data[n] & mask) != 0)
                            {
                                bits[i] = true;
                            }
                            n++;
                            i++;
                        }
                    }
                }
                else
                {
                    throw new DicomImagingException("Unable to extract embedded overlay from pixel data with bits stored greater than 16.");
                }

                return(new MemoryByteBuffer(bits.Array));
            }
        }
Ejemplo n.º 19
0
        internal static void Decode(
            DicomPixelData oldPixelData,
            DicomPixelData newPixelData,
            DicomJpegParams parameters)
        {
            var pixelCount = oldPixelData.Height * oldPixelData.Width;

            if (newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrIct
                || newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrRct)
            {
                newPixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb;
            }

            if (newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422
                || newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial422)
            {
                newPixelData.PhotometricInterpretation = PhotometricInterpretation.YbrFull;
            }

            if (newPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull)
            {
                newPixelData.PlanarConfiguration = PlanarConfiguration.Planar;
            }

            for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++)
            {
                var jpegData = oldPixelData.GetFrame(frame);

                // Destination frame should be of even length
                var frameSize = newPixelData.UncompressedFrameSize;
                if ((frameSize & 1) == 1) ++frameSize;
                var destArray = new byte[frameSize];

                using (var stream = new MemoryStream(jpegData.Data))
                {
                    var decoder = new JpegImage(stream);
                    var w = decoder.Width;
                    var h = decoder.Height;

                    for (var c = 0; c < decoder.ComponentsPerSample; c++)
                    {
                        var pos = newPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? (c * pixelCount) : c;
                        var offset = newPixelData.PlanarConfiguration == PlanarConfiguration.Planar
                                         ? 1
                                         : decoder.ComponentsPerSample;

                        if (newPixelData.BytesAllocated == 1)
                        {
                            for (var y = 0; y < h; ++y)
                            {
                                var row = decoder.GetRow(y);
                                for (var x = 0; x < w; ++x)
                                {
                                    destArray[pos] = (byte)row[x][c];
                                    pos += offset;
                                }
                            }
                        }
#if SUPPORT16BIT
                        else if (newPixelData.BytesAllocated == 2)
                        {
                            var destArray16 = new short[frameSize >> 1];
                            for (var y = 0; y < h; ++y)
                            {
                                var row = decoder.GetRow(y);
                                for (var x = 0; x < w; ++x)
                                {
                                    destArray16[pos] = row[x][c];
                                    pos += offset;
                                }
                            }

                            Buffer.BlockCopy(destArray16, 0, destArray, 0, frameSize);
                        }
#endif
                        else
                        {
                            throw new InvalidOperationException(
                                $"JPEG module does not support Bits Allocated == {newPixelData.BitsAllocated}!");
                        }
                    }

                    newPixelData.AddFrame(new MemoryByteBuffer(destArray));
                }
            }
        }
Ejemplo n.º 20
0
        internal static void Encode(
            DicomPixelData oldPixelData,
            DicomPixelData newPixelData,
            DicomJpegParams parameters)
        {
            if ((oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422)
                || (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial422)
                || (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrPartial420))
            {
                throw new InvalidOperationException(
                    "Photometric Interpretation '" + oldPixelData.PhotometricInterpretation
                    + "' not supported by JPEG encoder");
            }

            var w = oldPixelData.Width;
            var h = oldPixelData.Height;

            for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++)
            {
                var frameData = oldPixelData.GetFrame(frame);

                var nc = oldPixelData.SamplesPerPixel;
                var sgnd = oldPixelData.PixelRepresentation == PixelRepresentation.Signed;

                var rows = Enumerable.Range(0, h).Select(i => new short[w, nc]).ToArray();

                for (var c = 0; c < nc; c++)
                {
                    var pos = oldPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? (c * w * h) : c;
                    var offset = oldPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? 1 : nc;

                    if (oldPixelData.BytesAllocated == 1)
                    {
                        var data = frameData.Data;
                        if (sgnd)
                        {
                            if (oldPixelData.BitsStored < 8)
                            {
                                var sign = (byte)(1 << oldPixelData.HighBit);
                                var mask = (byte)(0xff >> (oldPixelData.BitsAllocated - oldPixelData.BitsStored));
                                for (var y = 0; y < h; ++y)
                                {
                                    for (var x = 0; x < w; ++x)
                                    {
                                        var pixel = (sbyte)data[pos];
                                        rows[y][x, c] = (short)((pixel & sign) > 0 ? -(((-pixel) & mask) + 1) : pixel);
                                        pos += offset;
                                    }
                                }
                            }
                            else
                            {
                                for (var y = 0; y < h; ++y)
                                {
                                    for (var x = 0; x < w; ++x)
                                    {
                                        rows[y][x, c] = (sbyte)data[pos];
                                        pos += offset;
                                    }
                                }
                            }
                        }
                        else
                        {
                            for (var y = 0; y < h; ++y)
                            {
                                for (var x = 0; x < w; ++x)
                                {
                                    rows[y][x, c] = data[pos];
                                    pos += offset;
                                }
                            }
                        }
                    }
#if SUPPORT16BIT
                    else if (oldPixelData.BytesAllocated == 2)
                    {
                        if (sgnd)
                        {
                            if (oldPixelData.BitsStored < 16)
                            {
                                var frameData16 = new ushort[w * h];
                                Buffer.BlockCopy(frameData.Data, 0, frameData16, 0, (int)frameData.Size);

                                var sign = (ushort)(1 << oldPixelData.HighBit);
                                var mask = (ushort)(0xffff >> (oldPixelData.BitsAllocated - oldPixelData.BitsStored));
                                for (var y = 0; y < h; ++y)
                                {
                                    for (var x = 0; x < w; ++x)
                                    {
                                        var pixel = frameData16[pos];
                                        rows[y][x, c] = (short)((pixel & sign) > 0 ? -(((-pixel) & mask) + 1) : pixel);
                                        pos += offset;
                                    }
                                }
                            }
                            else
                            {
                                var frameData16 = new short[w * h];
                                Buffer.BlockCopy(frameData.Data, 0, frameData16, 0, (int)frameData.Size);

                                for (var y = 0; y < h; ++y)
                                {
                                    for (var x = 0; x < w; ++x)
                                    {
                                        rows[y][x, c] = frameData16[pos];
                                        pos += offset;
                                    }
                                }
                            }
                        }
                        else
                        {
                            var frameData16 = new ushort[w * h];
                            Buffer.BlockCopy(frameData.Data, 0, frameData16, 0, (int)frameData.Size);

                            for (var y = 0; y < h; ++y)
                            {
                                for (var x = 0; x < w; ++x)
                                {
                                    rows[y][x, c] = (short)frameData16[pos];
                                    pos += offset;
                                }
                            }
                        }
                    }
#endif
                    else
                    {
                        throw new InvalidOperationException(
                            $"JPEG codec does not support Bits Allocated == {oldPixelData.BitsAllocated}");
                    }
                }

                try
                {
                    using (var stream = new MemoryStream())
                    {
                        var sampleRows =
                            rows.Select(
                                row =>
                                new SampleRow(
                                    ToRawRow(row, oldPixelData.BitsAllocated),
                                    w,
                                    (byte)oldPixelData.BitsStored,
                                    (byte)nc)).ToArray();
                        var colorSpace = GetColorSpace(oldPixelData.PhotometricInterpretation);
                        using (var encoder = new JpegImage(sampleRows, colorSpace))
                        {
                            encoder.WriteJpeg(stream, ToCompressionParameters(parameters));
                        }
                        newPixelData.AddFrame(new MemoryByteBuffer(stream.ToArray()));
                    }
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException("Unable to JPEG encode image", e);
                }
            }

            if (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.Rgb)
            {
                newPixelData.PlanarConfiguration = PlanarConfiguration.Interleaved;
            }
        }