Beispiel #1
0
        public static IEnumerable <(string ChannelId, DicomFolderContents Content)> DecompressSegmentationData(Stream inputStream)
        {
            var files = DicomCompressionHelpers.DecompressPayload(inputStream);
            var dictionaryChannelToFiles = new Dictionary <string, List <byte[]> >();

            foreach ((string filename, byte[] data) in files)
            {
                var channelId = filename.Split(DicomCompressionHelpers.ChannelIdAndDicomSeriesSeparator).First();

                if (!dictionaryChannelToFiles.ContainsKey(channelId))
                {
                    dictionaryChannelToFiles.Add(channelId, new List <byte[]>());
                }

                dictionaryChannelToFiles[channelId].Add(data);
            }

            var result = new List <(string ChannelId, DicomFolderContents content)>();

            foreach (var item in dictionaryChannelToFiles)
            {
                var fileAndPaths = item.Value
                                   .Select(x => DicomFileAndPath.SafeCreate(new MemoryStream(x), string.Empty))
                                   .ToList();
                result.Add((item.Key, DicomFolderContents.Build(fileAndPaths)));
            }

            return(result);
        }
Beispiel #2
0
 /// <summary>
 /// Opens the given byte array as a Zip archive, and returns Dicom files for all entries
 /// in the archive.
 /// </summary>
 /// <param name="zipArchive">The full Zip archive as a byte array.</param>
 /// <returns></returns>
 public static IEnumerable <DicomFileAndPath> DicomFilesFromZipArchive(byte[] zipArchive)
 {
     using (var zip = new ZipArchive(new MemoryStream(zipArchive), ZipArchiveMode.Read))
     {
         foreach (var entry in zip.Entries)
         {
             yield return(DicomFileAndPath.SafeCreate(new MemoryStream(ToByteArray(entry)), string.Empty));
         }
     }
 }
        /// <summary>
        /// Saves a medical scan to a set of Dicom files. Each file is saved into a memory stream.
        /// The returned Dicom files have the Path property set to {sliceIndex}.dcm.
        /// Use with extreme care - many Dicom elements have to be halluzinated here, and there's no
        /// guarantee that the resulting Dicom will be usable beyond what is needed in InnerEye.
        /// </summary>
        /// <param name="scan">The medical scan.</param>
        /// <param name="imageModality">The image modality through which the scan was acquired.</param>
        /// <param name="seriesDescription">The series description that should be used in the Dicom files.</param>
        /// <param name="patientID">The patient ID that should be used in the Dicom files. If null,
        /// a randomly generated patient ID will be used.</param>
        /// <param name="studyInstanceID">The study ID that should be used in the Dicom files (DicomTag.StudyInstanceUID). If null,
        /// a randomly generated study ID will be used.</param>
        /// <param name="additionalDicomItems">Additional Dicom items that will be added to each of the slice datasets. This can
        /// be used to pass in additional information like manufacturer.</param>
        /// <returns></returns>
        public static List <DicomFileAndPath> ScanToDicomInMemory(Volume3D <short> scan,
                                                                  ImageModality imageModality,
                                                                  string seriesDescription          = null,
                                                                  string patientID                  = null,
                                                                  string studyInstanceID            = null,
                                                                  DicomDataset additionalDicomItems = null)
        {
            var scanAsDicomFiles = Convert(scan, imageModality, seriesDescription, patientID, studyInstanceID, additionalDicomItems).ToList();
            var dicomFileAndPath = new List <DicomFileAndPath>();

            for (var index = 0; index < scanAsDicomFiles.Count; index++)
            {
                var stream = new MemoryStream();
                scanAsDicomFiles[index].Save(stream);
                stream.Seek(0, SeekOrigin.Begin);
                var dicomFile = DicomFileAndPath.SafeCreate(stream, $"{index}.dcm");
                dicomFileAndPath.Add(dicomFile);
            }
            return(dicomFileAndPath);
        }
        /// <summary>
        /// Convert from Nifti format to DICOM-RT format.
        /// </summary>
        /// <param name="niftiFilename">Nifti input filename.</param>
        /// <param name="referenceSeries">Path to folder of reference DICOM files.</param>
        /// <param name="structureNames">Names for each structure.</param>
        /// <param name="structureColors">Colors for each structure, defaults to red if this array smaller than list of structures.</param>
        /// <param name="fillHoles">Flags to enable fill holes for each structure, defaults to false this array smaller than list of structures..</param>
        /// <param name="dcmFilename">Target output file.</param>
        public static void ConvertNiftiToDicom(
            string niftiFilename,
            string referenceSeries,
            string[] structureNames,
            RGBColorOption?[] structureColors,
            bool?[] fillHoles,
            ROIInterpretedType[] roiInterpretedTypes,
            string dcmFilename,
            string modelNameAndVersion,
            string manufacturer,
            string interpreter)
        {
            var sourceVolume = MedIO.LoadNiftiAsByte(niftiFilename);

            Trace.TraceInformation($"Loaded NIFTI from {niftiFilename}");

            var labels = VolumeMetadataMapper.MultiLabelMapping(sourceVolume, structureNames.Length);
            var volumesWithMetadata = VolumeMetadataMapper.MapVolumeMetadata(labels, structureNames, structureColors, fillHoles, roiInterpretedTypes);

            var referenceVolume = DicomSeriesHelpers.LoadVolume(
                DicomFolderContents.Build(
                    Directory.EnumerateFiles(referenceSeries).Select(x => DicomFileAndPath.SafeCreate(x)).ToList()
                    ));

            var outputEncoder = new DicomRTStructOutputEncoder();

            var outputStructureBytes = outputEncoder.EncodeStructures(
                volumesWithMetadata,
                new Dictionary <string, MedicalVolume>()
            {
                { "", referenceVolume }
            },
                modelNameAndVersion,
                manufacturer,
                interpreter);

            File.WriteAllBytes(dcmFilename, outputStructureBytes.Array);
        }
        public void RtStructOutputEncoder_SuccessWithValidInputs()
        {
            var labels = VolumeMetadataMapper.MultiLabelMapping(sourceVolume, NumValidLabels);
            var volumesWithMetadata = VolumeMetadataMapper.MapVolumeMetadata(labels, StructureNames, StructureColors, FillHoles, ROIInterpretedTypes);

            var referenceVolume = DicomSeriesHelpers.LoadVolume(DicomFolderContents.Build(
                                                                    Directory.EnumerateFiles(TestDicomVolumeLocation).Select(x => DicomFileAndPath.SafeCreate(x)).ToList()
                                                                    ));

            var outputEncoder = new DicomRTStructOutputEncoder();

            var outputStructureBytes = outputEncoder.EncodeStructures(
                volumesWithMetadata,
                new Dictionary <string, MedicalVolume>()
            {
                { "", referenceVolume }
            },
                "modelX:1",
                "manufacturer",
                "interpreter");

            var dcm = DicomFile.Open(new MemoryStream(outputStructureBytes.Array));

            // Check the output format (should be RT struct)
            Assert.AreEqual(DicomUID.RTStructureSetStorage, dcm.FileMetaInfo.MediaStorageSOPClassUID);

            // Check stuff in StructureSet ROI sequence
            var structSetRois = dcm.Dataset.GetSequence(DicomTag.StructureSetROISequence).Items;
            var iter          = StructureNames.GetEnumerator();

            iter.MoveNext();

            var origReferencedFrameOfReference = referenceVolume.Identifiers.First().FrameOfReference.FrameOfReferenceUid;

            foreach (var roi in structSetRois)
            {
                // Verify that names in the generated DICOM Rt structure are the ones we've supplied
                Assert.AreEqual(iter.Current, roi.GetString(DicomTag.ROIName));
                iter.MoveNext();

                // Verify that this roi references the same frame of reference as the original image
                Assert.AreEqual(roi.GetString(DicomTag.ReferencedFrameOfReferenceUID), origReferencedFrameOfReference);
            }

            // Check stuff in ROI Contour sequence
            var roiContours = dcm.Dataset.GetSequence(DicomTag.ROIContourSequence).Items;
            var iterColors  = 0;

            var sopInstanceUIDs = referenceVolume.Identifiers.Select(x => x.Image.SopCommon.SopInstanceUid);

            foreach (var contourSequence in roiContours)
            {
                // Verify that colors in the generated contour sequence are the ones we've supplied
                var currentColor       = StructureColors[iterColors].Value;
                var currentColorString = string.Format("{0}\\{1}\\{2}", currentColor.R, currentColor.G, currentColor.B);

                Assert.AreEqual(contourSequence.GetString(DicomTag.ROIDisplayColor), currentColorString);
                iterColors++;

                // Verify that all contour types are closed planar
                Assert.IsTrue(contourSequence.GetSequence(DicomTag.ContourSequence).Items.All(
                                  x => x.GetString(DicomTag.ContourGeometricType) == "CLOSED_PLANAR"));

                // Verify that for all contours there exists a SOP Instance UID in the original series
                Assert.IsTrue(contourSequence.GetSequence(DicomTag.ContourSequence).Items.All(
                                  x => sopInstanceUIDs.Contains(x.GetSequence(DicomTag.ContourImageSequence).Items[0].GetString(DicomTag.ReferencedSOPInstanceUID))));
            }
        }