public async Task GivenSupportedAcceptHeaders_WhenRetrieveFrame_ThenServerShouldReturnExpectedContent(string testDataFolder, string mediaType, string transferSyntax) { TranscoderTestData transcoderTestData = TranscoderTestDataHelper.GetTestData(testDataFolder); DicomFile inputDicomFile = await DicomFile.OpenAsync(transcoderTestData.InputDicomFile); await EnsureFileIsStoredAsync(inputDicomFile); var instanceId = inputDicomFile.Dataset.ToInstanceIdentifier(); _studiesToClean.Add(instanceId.StudyInstanceUid); DicomFile outputDicomFile = DicomFile.Open(transcoderTestData.ExpectedOutputDicomFile); DicomPixelData pixelData = DicomPixelData.Create(outputDicomFile.Dataset); DicomWebResponse <IReadOnlyList <Stream> > response = await _client.RetrieveFramesAsync(instanceId.StudyInstanceUid, instanceId.SeriesInstanceUid, instanceId.SopInstanceUid, mediaType, transferSyntax, frames : new[] { 1 }); int frameIndex = 0; foreach (Stream item in response.Value) { // TODO: verify media type once https://microsofthealth.visualstudio.com/Health/_workitems/edit/75185 is done Assert.Equal(item.ToByteArray(), pixelData.GetFrame(frameIndex).Data); frameIndex++; } }
public async Task GivenUnsupportedTransferSyntax_WhenRetrieveFrameWithOriginalTransferSyntax_ThenOriginalContentReturned() { var studyInstanceUid = TestUidGenerator.Generate(); var seriesInstanceUid = TestUidGenerator.Generate(); var sopInstanceUid = TestUidGenerator.Generate(); DicomFile dicomFile = Samples.CreateRandomDicomFileWith8BitPixelData( studyInstanceUid, seriesInstanceUid, sopInstanceUid, transferSyntax: DicomTransferSyntax.HEVCH265Main10ProfileLevel51.UID.UID, encode: false); await InternalStoreAsync(new[] { dicomFile }); // Check for series DicomWebResponse <IReadOnlyList <Stream> > response = await _client.RetrieveFramesAsync( studyInstanceUid, seriesInstanceUid, sopInstanceUid, dicomTransferSyntax : "*", frames : new[] { 1 }); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(response.Value[0].ToByteArray(), DicomPixelData.Create(dicomFile.Dataset).GetFrame(0).Data); }
private static void TestRightAlignSigned(ushort[] testValues, int bitsStored, int highBit, short[] expectedValues, bool asBytes, bool asOpposingEndian) { TestRightAlign(ref testValues, bitsStored, highBit, asBytes, asOpposingEndian); var newHighBit = highBit - DicomPixelData.GetLowBit(bitsStored, highBit); Assert.AreEqual(expectedValues, DicomSignedToSigned(testValues, newHighBit)); }
public override void Encode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { DicomRleNativeCodec.Encode(oldPixelData.ToNativePixelData(), newPixelData.ToNativePixelData()); }
public async Task GivenMultipleFrames_WhenRetrieveFrame_ThenServerShouldReturnExpectedContent() { string studyInstanceUid = TestUidGenerator.Generate(); DicomFile dicomFile1 = Samples.CreateRandomDicomFileWithPixelData(studyInstanceUid, frames: 3); DicomPixelData pixelData = DicomPixelData.Create(dicomFile1.Dataset); InstanceIdentifier dicomInstance = dicomFile1.Dataset.ToInstanceIdentifier(); await InternalStoreAsync(new[] { dicomFile1 }); using DicomWebAsyncEnumerableResponse <Stream> response = await _client.RetrieveFramesAsync( dicomInstance.StudyInstanceUid, dicomInstance.SeriesInstanceUid, dicomInstance.SopInstanceUid, frames : new[] { 1, 2 }, dicomTransferSyntax : "*"); Stream[] frames = await response.ToArrayAsync(); Assert.NotNull(frames); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(2, frames.Length); Assert.Equal(KnownContentTypes.MultipartRelated, response.ContentHeaders.ContentType.MediaType); Assert.Equal(pixelData.GetFrame(0).Data, frames[0].ToByteArray()); Assert.Equal(pixelData.GetFrame(1).Data, frames[1].ToByteArray()); }
public async Task GivenUnsupportedTransferSyntax_WhenRetrieveFrameWithOriginalTransferSyntax_ThenOriginalContentReturned() { var studyInstanceUid = TestUidGenerator.Generate(); var seriesInstanceUid = TestUidGenerator.Generate(); var sopInstanceUid = TestUidGenerator.Generate(); DicomFile dicomFile = Samples.CreateRandomDicomFileWith8BitPixelData( studyInstanceUid, seriesInstanceUid, sopInstanceUid, transferSyntax: DicomTransferSyntax.HEVCH265Main10ProfileLevel51.UID.UID, encode: false); await InternalStoreAsync(new[] { dicomFile }); // Check for series using DicomWebAsyncEnumerableResponse <Stream> response = await _client.RetrieveFramesAsync( studyInstanceUid, seriesInstanceUid, sopInstanceUid, dicomTransferSyntax : "*", frames : new[] { 1 }); Stream[] results = await response.ToArrayAsync(); Assert.Collection( results, item => Assert.Equal(item.ToByteArray(), DicomPixelData.Create(dicomFile.Dataset).GetFrame(0).Data)); }
/// <summary> /// Initialize new instance of <seealso cref="PaletteColorPipeline"/> containing palette color LUT extracted from /// <paramref name="pixelData"/> /// </summary> /// <param name="pixelData">Dicom Pixel Data containing paletter color LUT</param> public PaletteColorPipeline(DicomPixelData pixelData) { var lut = pixelData.PaletteColorLUT; var first = pixelData.Dataset.Get<int>(DicomTag.RedPaletteColorLookupTableDescriptor, 1); _lut = new PaletteColorLUT(first, lut); }
private static DicomDataset Decode( DicomDataset oldDataset, DicomTransferSyntax outSyntax, IDicomCodec codec, DicomCodecParams parameters) { if (codec == null) { throw new DicomCodecException($"Decoding dataset with transfer syntax: {oldDataset.InternalTransferSyntax} is not supported."); } var oldPixelData = DicomPixelData.Create(oldDataset); var newDataset = oldDataset.Clone(); newDataset.InternalTransferSyntax = outSyntax; var newPixelData = DicomPixelData.Create(newDataset, true); codec.Decode(oldPixelData, newPixelData, parameters); ProcessOverlays(oldDataset, newDataset); newDataset.RecalculateGroupLengths(false); return(newDataset); }
public override void Encode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { DicomJpegCodecImpl.Encode(oldPixelData, newPixelData, parameters as DicomJpegParams); }
public static NativePixelData ToNativePixelData(this DicomPixelData dicomPixelData) { return(new NativePixelData { NumberOfFrames = dicomPixelData.NumberOfFrames, Width = dicomPixelData.Width, Height = dicomPixelData.Height, SamplesPerPixel = dicomPixelData.SamplesPerPixel, HighBit = dicomPixelData.HighBit, BitsStored = dicomPixelData.BitsStored, BitsAllocated = dicomPixelData.BitsAllocated, BytesAllocated = dicomPixelData.BytesAllocated, UncompressedFrameSize = dicomPixelData.UncompressedFrameSize, PlanarConfiguration = (int)dicomPixelData.PlanarConfiguration, PixelRepresentation = (int)dicomPixelData.PixelRepresentation, TransferSyntaxIsLossy = dicomPixelData.Syntax.IsLossy, PhotometricInterpretation = dicomPixelData.PhotometricInterpretation.Value, GetFrameImpl = index => dicomPixelData.GetFrame(index).Data, AddFrameImpl = buffer => dicomPixelData.AddFrame(new MemoryByteBuffer(buffer)), SetPlanarConfigurationImpl = value => dicomPixelData.PlanarConfiguration = (PlanarConfiguration)value, SetPhotometricInterpretationImpl = value => dicomPixelData.PhotometricInterpretation = PhotometricInterpretation.Parse(value) }); }
public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { throw new InvalidOperationException("Unsupported OS Platform"); } for (int frame = 0; frame < oldPixelData.NumberOfFrames; frame++) { IByteBuffer jpegData = oldPixelData.GetFrame(frame); //Converting photmetricinterpretation YbrFull or YbrFull422 to RGB if (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull) { jpegData = PixelDataConverter.YbrFullToRgb(jpegData); oldPixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb; } else if (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422) { jpegData = PixelDataConverter.YbrFull422ToRgb(jpegData, oldPixelData.Width); oldPixelData.PhotometricInterpretation = PhotometricInterpretation.Rgb; } PinnedByteArray jpegArray = new PinnedByteArray(jpegData.Data); byte[] frameData = new byte[newPixelData.UncompressedFrameSize]; PinnedByteArray frameArray = new PinnedByteArray(frameData); JlsParameters jls = new JlsParameters(); char[] errorMessage = new char[256]; // IMPORT JpegLsDecode unsafe { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { CharlsApiResultType err = JpegLSDecode_Linux64((void *)frameArray.Pointer, frameData.Length, (void *)jpegArray.Pointer, Convert.ToUInt32(jpegData.Size), ref jls, errorMessage); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { CharlsApiResultType err = JpegLSDecode_Windows64((void *)frameArray.Pointer, frameData.Length, (void *)jpegArray.Pointer, Convert.ToUInt32(jpegData.Size), ref jls, errorMessage); } IByteBuffer buffer; if (frameData.Length >= (1 * 1024 * 1024) || oldPixelData.NumberOfFrames > 1) { buffer = new TempFileBuffer(frameData); } else { buffer = new MemoryByteBuffer(frameData); } buffer = EvenLengthBuffer.Create(buffer); newPixelData.AddFrame(buffer); } } }
public static void LosslessImageTestWithConversion(TransferSyntax syntax, DicomFile theFile) { if (File.Exists(theFile.Filename)) { File.Delete(theFile.Filename); } DicomFile saveCopy = new DicomFile(theFile.Filename, theFile.MetaInfo.Copy(), theFile.DataSet.Copy()); theFile.ChangeTransferSyntax(syntax); theFile.Save(DicomWriteOptions.ExplicitLengthSequence); DicomFile newFile = new DicomFile(theFile.Filename); newFile.Load(DicomReadOptions.Default); newFile.ChangeTransferSyntax(saveCopy.TransferSyntax); string failureDescription; bool result = Compare(DicomPixelData.CreateFrom(newFile), DicomPixelData.CreateFrom(saveCopy), out failureDescription); Assert.IsTrue(result, failureDescription); Assert.IsFalse(newFile.DataSet.Equals(saveCopy.DataSet)); }
public static void AppendRandomPixelData(int rows, int columns, int frames, params DicomFile[] dicomFiles) { EnsureArg.IsGte(rows, 0, nameof(rows)); EnsureArg.IsGte(columns, 0, nameof(columns)); EnsureArg.IsNotNull(dicomFiles, nameof(dicomFiles)); var pixelDataSize = rows * columns; const ushort bitsAllocated = 8; dicomFiles.Each(x => { x.Dataset.AddOrUpdate(DicomTag.Rows, (ushort)rows); x.Dataset.AddOrUpdate(DicomTag.Columns, (ushort)columns); x.Dataset.AddOrUpdate(DicomTag.BitsAllocated, bitsAllocated); var pixelData = DicomPixelData.Create(x.Dataset, true); pixelData.SamplesPerPixel = 1; pixelData.PixelRepresentation = PixelRepresentation.Unsigned; pixelData.BitsStored = bitsAllocated; pixelData.HighBit = bitsAllocated - 1; for (var i = 0; i < frames; i++) { pixelData.AddFrame(CreateRandomPixelData(pixelDataSize)); } }); }
public async Task <IReadOnlyCollection <Stream> > GetFramesResourceAsync(Stream stream, IEnumerable <int> frames, bool originalTransferSyntaxRequested, string requestedRepresentation) { EnsureArg.IsNotNull(stream, nameof(stream)); EnsureArg.IsNotNull(frames, nameof(frames)); DicomFile dicomFile = await DicomFile.OpenAsync(stream); // Validate requested frame index exists in file and retrieve the pixel data associated with the file. DicomPixelData pixelData = dicomFile.GetPixelDataAndValidateFrames(frames); if (!originalTransferSyntaxRequested && !dicomFile.Dataset.InternalTransferSyntax.Equals(DicomTransferSyntax.Parse(requestedRepresentation))) { return(frames.Select(frame => new LazyTransformReadOnlyStream <DicomFile>( dicomFile, df => _transcoder.TranscodeFrame(df, frame, requestedRepresentation))) .ToArray()); } else { return(frames.Select( frame => new LazyTransformReadOnlyStream <DicomFile>( dicomFile, df => GetFrameAsDicomData(pixelData, frame))) .ToArray()); } }
public override void Encode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { if (oldPixelData.NumberOfFrames == 0) return; // IJG eats the extra padding bits. Is there a better way to test for this? if (oldPixelData.BitsAllocated == 16 && oldPixelData.BitsStored <= 8) { // check for embedded overlays? newPixelData.BitsAllocated = 8; } var jparams = parameters as DicomJpegParams ?? GetDefaultParameters() as DicomJpegParams; var codec = GetCodec(oldPixelData.BitsStored, jparams); var oldNativeData = oldPixelData.ToNativePixelData(); var newNativeData = newPixelData.ToNativePixelData(); var jNativeParams = jparams.ToNativeJpegParameters(); for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++) { codec.Encode(oldNativeData, newNativeData, jNativeParams, frame); } }
public override void Encode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { if (oldPixelData.NumberOfFrames == 0) { return; } // IJG eats the extra padding bits. Is there a better way to test for this? if (oldPixelData.BitsAllocated == 16 && oldPixelData.BitsStored <= 8) { // check for embedded overlays? newPixelData.BitsAllocated = 8; } var jparams = parameters as DicomJpegParams ?? GetDefaultParameters() as DicomJpegParams; var codec = GetCodec(oldPixelData.BitsStored, jparams); var oldNativeData = oldPixelData.ToNativePixelData(); var newNativeData = newPixelData.ToNativePixelData(); var jNativeParams = jparams.ToNativeJpegParameters(); for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++) { codec.Encode(oldNativeData, newNativeData, jNativeParams, frame); } }
/// <summary> /// Create <see cref="IPixelData"/> form <see cref="DicomPixelData"/> /// according to the input <paramref name="pixelData"/> <seealso cref="PhotometricInterpretation"/> /// </summary> /// <param name="pixelData">Input pixel data</param> /// <param name="frame">Frame number (0 based)</param> /// <returns>Implementation of <seealso cref="IPixelData"/> according to <seealso cref="PhotometricInterpretation"/></returns> public static IPixelData Create(DicomPixelData pixelData, int frame) { PhotometricInterpretation pi = pixelData.PhotometricInterpretation; if (pi == null) { // generally ACR-NEMA var samples = pixelData.SamplesPerPixel; if (samples == 0 || samples == 1) { if (pixelData.Dataset.Contains(DicomTag.RedPaletteColorLookupTableData)) pi = PhotometricInterpretation.PaletteColor; else pi = PhotometricInterpretation.Monochrome2; } else { // assume, probably incorrectly, that the image is RGB pi = PhotometricInterpretation.Rgb; } } if (pixelData.BitsStored == 1) { if (pixelData.Dataset.Get<DicomUID>(DicomTag.SOPClassUID) == DicomUID.MultiFrameSingleBitSecondaryCaptureImageStorage) // Multi-frame Single Bit Secondary Capture is stored LSB -> MSB return new SingleBitPixelData(pixelData.Width, pixelData.Height, PixelDataConverter.ReverseBits(pixelData.GetFrame(frame))); else // Need sample images to verify that this is correct return new SingleBitPixelData(pixelData.Width, pixelData.Height, pixelData.GetFrame(frame)); } else if (pi == PhotometricInterpretation.Monochrome1 || pi == PhotometricInterpretation.Monochrome2 || pi == PhotometricInterpretation.PaletteColor) { if (pixelData.BitsAllocated <= 8) return new GrayscalePixelDataU8(pixelData.Width, pixelData.Height, pixelData.GetFrame(frame)); else if (pixelData.BitsAllocated <= 16) { if (pixelData.PixelRepresentation == PixelRepresentation.Signed) return new GrayscalePixelDataS16(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); else return new GrayscalePixelDataU16(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); } else if (pixelData.BitsAllocated <= 32) { if (pixelData.PixelRepresentation == PixelRepresentation.Signed) return new GrayscalePixelDataS32(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); else return new GrayscalePixelDataU32(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); } else throw new DicomImagingException("Unsupported pixel data value for bits stored: {0}", pixelData.BitsStored); } else if (pi == PhotometricInterpretation.Rgb || pi == PhotometricInterpretation.YbrFull || pi == PhotometricInterpretation.YbrFull422 || pi == PhotometricInterpretation.YbrPartial422) { var buffer = pixelData.GetFrame(frame); if (pixelData.PlanarConfiguration == PlanarConfiguration.Planar) buffer = PixelDataConverter.PlanarToInterleaved24(buffer); if (pi == PhotometricInterpretation.YbrFull) buffer = PixelDataConverter.YbrFullToRgb(buffer); else if (pi == PhotometricInterpretation.YbrFull422) buffer = PixelDataConverter.YbrFull422ToRgb(buffer); else if (pi == PhotometricInterpretation.YbrPartial422) buffer = PixelDataConverter.YbrPartial422ToRgb(buffer); return new ColorPixelData24(pixelData.Width, pixelData.Height, buffer); } else { throw new DicomImagingException("Unsupported pixel data photometric interpretation: {0}", pi.Value); } }
public override void Encode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { var pixelCount = oldPixelData.Width * oldPixelData.Height; var numberOfSegments = oldPixelData.BytesAllocated * oldPixelData.SamplesPerPixel; for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++) { var frameData = oldPixelData.GetFrame(frame); var frameArray = frameData.Data; using (var encoder = new RLEEncoder()) { for (var s = 0; s < numberOfSegments; s++) { encoder.NextSegment(); var sample = s / oldPixelData.BytesAllocated; var sabyte = s % oldPixelData.BytesAllocated; int pos; int offset; if (newPixelData.PlanarConfiguration == PlanarConfiguration.Interleaved) { pos = sample * oldPixelData.BytesAllocated; offset = numberOfSegments; } else { pos = sample * oldPixelData.BytesAllocated * pixelCount; offset = oldPixelData.BytesAllocated; } pos += oldPixelData.BytesAllocated - sabyte - 1; for (var p = 0; p < pixelCount; p++) { if (pos >= frameArray.Length) { throw new InvalidOperationException("Read position is past end of frame buffer"); } encoder.Encode(frameArray[pos]); pos += offset; } encoder.Flush(); } encoder.MakeEvenLength(); var data = encoder.GetBuffer(); newPixelData.AddFrame(data); } } }
public override void Encode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { DicomJpeg2000NativeCodec.Encode( oldPixelData.ToNativePixelData(), newPixelData.ToNativePixelData(), parameters.ToNativeJpeg2000Parameters()); }
public override void Decode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { DicomJpegLsNativeCodec.Decode( oldPixelData.ToNativePixelData(), newPixelData.ToNativePixelData(), parameters.ToNativeJpegLSParameters()); }
public override void Decode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++) { var rleData = oldPixelData.GetFrame(frame); // Create new frame data of even length var frameSize = newPixelData.UncompressedFrameSize; if ((frameSize & 1) == 1) { ++frameSize; } var frameData = new MemoryByteBuffer(new byte[frameSize]); var pixelCount = oldPixelData.Width * oldPixelData.Height; var numberOfSegments = oldPixelData.BytesAllocated * oldPixelData.SamplesPerPixel; var decoder = new RLEDecoder(rleData); if (decoder.NumberOfSegments != numberOfSegments) { throw new InvalidOperationException("Unexpected number of RLE segments!"); } for (var s = 0; s < numberOfSegments; s++) { var sample = s / newPixelData.BytesAllocated; var sabyte = s % newPixelData.BytesAllocated; int pos, offset; if (newPixelData.PlanarConfiguration == PlanarConfiguration.Interleaved) { pos = sample * newPixelData.BytesAllocated; offset = newPixelData.SamplesPerPixel * newPixelData.BytesAllocated; } else { pos = sample * newPixelData.BytesAllocated * pixelCount; offset = newPixelData.BytesAllocated; } pos += newPixelData.BytesAllocated - sabyte - 1; decoder.DecodeSegment(s, frameData, pos, offset); } newPixelData.AddFrame(frameData); } }
public override void Encode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { #if NETFX_CORE DicomJpeg2000NativeCodec.Encode( oldPixelData.ToNativePixelData(), newPixelData.ToNativePixelData(), parameters.ToNativeJpeg2000Parameters()); #else DicomJpeg2000CodecImpl.Encode(oldPixelData, newPixelData, parameters as DicomJpeg2000Params); #endif }
/// <summary> /// Create <see cref="IPixelData"/> form <see cref="DicomPixelData"/> /// according to the input <paramref name="pixelData"/> <seealso cref="PhotometricInterpretation"/> /// </summary> /// <param name="pixelData">Input pixel data</param> /// <param name="frame">Frame number (0 based)</param> /// <returns>Implementation of <seealso cref="IPixelData"/> according to <seealso cref="PhotometricInterpretation"/></returns> public static IPixelData Create(DicomPixelData pixelData, int frame) { PhotometricInterpretation pi = pixelData.PhotometricInterpretation; if (pi == null) { // generally ACR-NEMA var samples = pixelData.SamplesPerPixel; if (samples == 0 || samples == 1) { if (pixelData.Dataset.Contains(DicomTag.RedPaletteColorLookupTableData)) pi = PhotometricInterpretation.PaletteColor; else pi = PhotometricInterpretation.Monochrome2; } else { // assume, probably incorrectly, that the image is RGB pi = PhotometricInterpretation.Rgb; } } if (pi == PhotometricInterpretation.Monochrome1 || pi == PhotometricInterpretation.Monochrome2 || pi == PhotometricInterpretation.PaletteColor) { if (pixelData.BitsAllocated <= 8) return new GrayscalePixelDataU8(pixelData.Width, pixelData.Height, pixelData.GetFrame(frame)); else if (pixelData.BitsAllocated <= 16) { if (pixelData.PixelRepresentation == PixelRepresentation.Signed) return new GrayscalePixelDataS16(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); else return new GrayscalePixelDataU16(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); } else if (pixelData.BitsAllocated <= 32) { if (pixelData.PixelRepresentation == PixelRepresentation.Signed) return new GrayscalePixelDataS32(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); else return new GrayscalePixelDataU32(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); } else throw new DicomImagingException("Unsupported pixel data value for bits stored: {0}", pixelData.BitsStored); } else if (pi == PhotometricInterpretation.Rgb || pi == PhotometricInterpretation.YbrFull) { var buffer = pixelData.GetFrame(frame); if (pixelData.PlanarConfiguration == PlanarConfiguration.Planar) buffer = PixelDataConverter.PlanarToInterleaved24(buffer); return new ColorPixelData24(pixelData.Width, pixelData.Height, buffer); } else if (pi == PhotometricInterpretation.YbrFull422) { var buffer = pixelData.GetFrame(frame); if (pixelData.PlanarConfiguration == PlanarConfiguration.Planar) throw new DicomImagingException("Unsupported planar configuration for YBR_FULL_422"); return new ColorPixelData24(pixelData.Width, pixelData.Height, buffer); } else { throw new DicomImagingException("Unsupported pixel data photometric interpretation: {0}", pi.Value); } }
public override void Decode( DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters) { if (oldPixelData.NumberOfFrames == 0) return; // IJG eats the extra padding bits. Is there a better way to test for this? if (newPixelData.BitsAllocated == 16 && newPixelData.BitsStored <= 8) { // check for embedded overlays here or below? newPixelData.BitsAllocated = 8; } var jparams = parameters as DicomJpegParams ?? GetDefaultParameters() as DicomJpegParams; var oldNativeData = oldPixelData.ToNativePixelData(); int precision; try { try { precision = JpegHelper.ScanJpegForBitDepth(oldPixelData); } catch { // if the internal scanner chokes on an image, try again using ijg precision = new Jpeg12Codec(JpegMode.Baseline, 0, 0).ScanHeaderForPrecision(oldNativeData); } } catch { // the old scanner choked on several valid images... // assume the correct encoder was used and let libijg handle the rest precision = oldPixelData.BitsStored; } if (newPixelData.BitsStored <= 8 && precision > 8) newPixelData.BitsAllocated = 16; // embedded overlay? var codec = GetCodec(precision, jparams); var newNativeData = newPixelData.ToNativePixelData(); var jNativeParams = jparams.ToNativeJpegParameters(); for (var frame = 0; frame < oldPixelData.NumberOfFrames; frame++) { codec.Decode(oldNativeData, newNativeData, jNativeParams, frame); } }
public abstract void Encode(DicomPixelData oldPixelData, DicomPixelData newPixelData, DicomCodecParams parameters);
//DCMTK djcodecd.cxx public static int ScanJpegForBitDepth(DicomPixelData pixelData) { DicomFragmentSequence element = pixelData.Dataset.Get<DicomFragmentSequence>(DicomTag.PixelData); IByteBuffer buffer = element.Fragments[0]; MemoryStream ms = new MemoryStream(buffer.Data); BinaryReader br = EndianBinaryReader.Create(ms, Endian.Big); long length = ms.Length; while (ms.Position < length) { ushort marker = br.ReadUInt16(); switch (marker) { case 0xffc0: // SOF_0: JPEG baseline case 0xffc1: // SOF_1: JPEG extended sequential DCT case 0xffc2: // SOF_2: JPEG progressive DCT case 0xffc3: // SOF_3: JPEG lossless sequential case 0xffc5: // SOF_5: differential (hierarchical) extended sequential, Huffman case 0xffc6: // SOF_6: differential (hierarchical) progressive, Huffman case 0xffc7: // SOF_7: differential (hierarchical) lossless, Huffman ms.Seek(2, SeekOrigin.Current); return (int)br.ReadByte(); case 0xffc8: // Reserved for JPEG extentions ms.Seek(br.ReadUInt16() - 2, SeekOrigin.Current); break; case 0xffc9: // SOF_9: extended sequential, arithmetic case 0xffca: // SOF_10: progressive, arithmetic case 0xffcb: // SOF_11: lossless, arithmetic case 0xffcd: // SOF_13: differential (hierarchical) extended sequential, arithmetic case 0xffce: // SOF_14: differential (hierarchical) progressive, arithmetic case 0xffcf: // SOF_15: differential (hierarchical) lossless, arithmetic ms.Seek(2, SeekOrigin.Current); return (int)br.ReadByte(); case 0xffc4: // DHT case 0xffcc: // DAC ms.Seek(br.ReadUInt16() - 2, SeekOrigin.Current); break; case 0xffd0: // RST m case 0xffd1: case 0xffd2: case 0xffd3: case 0xffd4: case 0xffd5: case 0xffd6: case 0xffd7: case 0xffd8: // SOI case 0xffd9: // EOI break; case 0xffda: // SOS case 0xffdb: // DQT case 0xffdc: // DNL case 0xffdd: // DRI case 0xffde: // DHP case 0xffdf: // EXP case 0xffe0: // APPn case 0xffe1: case 0xffe2: case 0xffe3: case 0xffe4: case 0xffe5: case 0xffe6: case 0xffe7: case 0xffe8: case 0xffe9: case 0xffea: case 0xffeb: case 0xffec: case 0xffed: case 0xffee: case 0xffef: case 0xfff0: // JPGn case 0xfff1: case 0xfff2: case 0xfff3: case 0xfff4: case 0xfff5: case 0xfff6: case 0xfff7: case 0xfff8: case 0xfff9: case 0xfffa: case 0xfffb: case 0xfffc: case 0xfffd: case 0xfffe: // COM ms.Seek(br.ReadUInt16() - 2, SeekOrigin.Current); break; case 0xff01: // TEM break; default: int b1 = br.ReadByte(); int b2 = br.ReadByte(); if (b1 == 0xff && b2 > 2 && b2 <= 0xbf) // RES reserved markers break; else throw new DicomCodecException("Unable to determine bit depth: JPEG syntax error!"); } } throw new DicomCodecException("Unable to determine bit depth: no JPEG SOF marker found!"); }
public static IPixelData Create(DicomPixelData pixelData, int frame) { PhotometricInterpretation pi = pixelData.PhotometricInterpretation; if (pi == PhotometricInterpretation.Monochrome1 || pi == PhotometricInterpretation.Monochrome2 || pi == PhotometricInterpretation.PaletteColor) { if (pixelData.BitsStored <= 8) return new GrayscalePixelDataU8(pixelData.Width, pixelData.Height, pixelData.GetFrame(frame)); else if (pixelData.BitsStored <= 16) { if (pixelData.PixelRepresentation == PixelRepresentation.Signed) return new GrayscalePixelDataS16(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); else return new GrayscalePixelDataU16(pixelData.Width, pixelData.Height, pixelData.BitDepth, pixelData.GetFrame(frame)); } else throw new DicomImagingException("Unsupported pixel data value for bits stored: {0}", pixelData.BitsStored); } else if (pi == PhotometricInterpretation.Rgb || pi == PhotometricInterpretation.YbrFull) { var buffer = pixelData.GetFrame(frame); if (pixelData.PlanarConfiguration == PlanarConfiguration.Planar) buffer = PixelDataConverter.PlanarToInterleaved24(buffer); return new ColorPixelData24(pixelData.Width, pixelData.Height, buffer); } else { throw new DicomImagingException("Unsupported pixel data photometric interpretation: {0}", pi.Value); } }
public static bool Compare(DicomPixelData pixels1, DicomPixelData pixels2, out string failureDescription) { failureDescription = string.Empty; if (pixels1.BitsAllocated != pixels2.BitsAllocated) { failureDescription = String.Format("Tag (7fe0,0010) Pixel Data: Bits Allocated varies: {0} , {1}", pixels1.BitsAllocated, pixels2.BitsAllocated); return false; } if (pixels1.BitsStored != pixels2.BitsStored) { failureDescription = String.Format("Tag (7fe0,0010) Pixel Data: Bits Stored varies: {0} , {1}", pixels1.BitsStored, pixels2.BitsStored); return false; } if (pixels1.ImageHeight != pixels2.ImageHeight) { failureDescription = String.Format("Tag (7fe0,0010) Pixel Data: Rows varies: {0} , {1}", pixels1.ImageHeight, pixels2.ImageHeight); return false; } if (pixels1.ImageWidth != pixels2.ImageWidth) { failureDescription = String.Format("Tag (7fe0,0010) Pixel Data: Columns varies: {0} , {1}", pixels1.ImageWidth, pixels2.ImageWidth); return false; } if (pixels1.SamplesPerPixel != pixels2.SamplesPerPixel) { failureDescription = String.Format("Tag (7fe0,0010) Pixel Data: Samples per pixel varies: {0} , {1}", pixels1.SamplesPerPixel, pixels2.SamplesPerPixel); return false; } if (pixels1.NumberOfFrames != pixels2.NumberOfFrames) { failureDescription = String.Format("Tag (7fe0,0010) Pixel Data: Number of frames varies: {0} , {1}", pixels1.NumberOfFrames, pixels2.NumberOfFrames); return false; } long pixelsVarying = 0; long totalVariation = 0; int pixels = pixels1.ImageHeight * pixels1.ImageWidth * pixels1.SamplesPerPixel; if (pixels1.BitsAllocated == 8) { for (int frame = 0; frame < pixels1.NumberOfFrames; frame++) { byte[] pixel1 = pixels1.GetFrame(frame); byte[] pixel2 = pixels2.GetFrame(frame); if (pixels1.HighBit != pixels2.HighBit) { // Justify the pixel, if needed if (DicomUncompressedPixelData.RightAlign(pixel1, pixels1.BitsAllocated, pixels1.BitsStored, pixels1.HighBit)) { //pixels1.HighBit = (ushort)(pixels1.BitsStored - 1); DicomUncompressedPixelData.ZeroUnusedBits(pixel1, pixels1.BitsAllocated, pixels1.BitsStored, pixels1.BitsStored - 1); } if (DicomUncompressedPixelData.RightAlign(pixel2, pixels2.BitsAllocated, pixels2.BitsStored, pixels2.HighBit)) { //pixels2.HighBit = (ushort)(pixels2.BitsStored - 1); DicomUncompressedPixelData.ZeroUnusedBits(pixel2, pixels2.BitsAllocated, pixels2.BitsStored, pixels2.BitsStored - 1); } } int[] intPixels1 = pixels1.IsSigned ? Convert8BitSigned(pixel1, pixels, (DicomUncompressedPixelData)pixels1) : Convert8BitUnsigned(pixel1, pixels, (DicomUncompressedPixelData)pixels1); int[] intPixels2 = pixels2.IsSigned ? Convert8BitSigned(pixel2, pixels, (DicomUncompressedPixelData)pixels2) : Convert8BitUnsigned(pixel2, pixels, (DicomUncompressedPixelData)pixels2); for (int i = 0; i < pixels; i++) if (intPixels1[i] != intPixels2[i]) { pixelsVarying++; totalVariation += Math.Abs(intPixels1[i] - intPixels2[i]); } } if (pixelsVarying > 0) { failureDescription = String.Format( "Tag (7fe0,0010) Pixel Data: {0} of {1} pixels varying, average difference: {2}", pixelsVarying, pixels * pixels1.NumberOfFrames, totalVariation / pixelsVarying); return false; } } else { for (int frame = 0; frame < pixels1.NumberOfFrames; frame++) { byte[] pixel1 = pixels1.GetFrame(frame); byte[] pixel2 = pixels2.GetFrame(frame); if (pixels1.HighBit != pixels2.HighBit) { // Justify the pixel, if needed if (DicomUncompressedPixelData.RightAlign(pixel1, pixels1.BitsAllocated, pixels1.BitsStored, pixels1.HighBit)) { //pixels1.HighBit = (ushort) (pixels1.BitsStored - 1); DicomUncompressedPixelData.ZeroUnusedBits(pixel1, pixels1.BitsAllocated, pixels1.BitsStored, pixels1.BitsStored - 1); } if (DicomUncompressedPixelData.RightAlign(pixel2, pixels2.BitsAllocated, pixels2.BitsStored, pixels2.HighBit)) { //pixels2.HighBit = (ushort)(pixels2.BitsStored - 1); DicomUncompressedPixelData.ZeroUnusedBits(pixel2, pixels2.BitsAllocated, pixels2.BitsStored, pixels2.BitsStored - 1); } } int[] intPixels1 = pixels1.IsSigned ? Convert16BitSigned(pixel1, pixels, (DicomUncompressedPixelData)pixels1) : Convert16BitUnsigned(pixel1, pixels, (DicomUncompressedPixelData)pixels1); int[] intPixels2 = pixels2.IsSigned ? Convert16BitSigned(pixel2, pixels, (DicomUncompressedPixelData)pixels2) : Convert16BitUnsigned(pixel2, pixels, (DicomUncompressedPixelData)pixels2); for (int i = 0; i < pixels; i++) if (intPixels1[i] != intPixels2[i]) { pixelsVarying++; totalVariation += Math.Abs(intPixels1[i] - intPixels2[i]); } } if (pixelsVarying > 0) { failureDescription = String.Format("Tag (7fe0,0010) Pixel Data: {0} of {1} pixels varying, average difference: {2}", pixelsVarying, pixels, totalVariation / pixelsVarying); return false; } } return true; }