/// <summary> /// Creates and populates a <see cref="Volume"/> from the builder's source frames. /// </summary> public Volume Build() { PrepareFrames(_frames); // this also sorts the frames into order by slice location // Construct a model SOP data source based on the first frame's DICOM header var sopDataSourcePrototype = VolumeSopDataSourcePrototype.Create(_frames.Select(f => (IDicomAttributeProvider)f.Sop.DataSource).ToList(), 16, 16, false); // compute normalized modality LUT double normalizedSlope, normalizedIntercept; ComputeNormalizedModalityLut(_frames, out normalizedSlope, out normalizedIntercept); sopDataSourcePrototype[DicomTags.RescaleSlope].SetFloat64(0, normalizedSlope); sopDataSourcePrototype[DicomTags.RescaleIntercept].SetFloat64(0, normalizedIntercept); sopDataSourcePrototype[DicomTags.RescaleType] = _frames[0].Sop.DataSource[DicomTags.RescaleType].Copy(); sopDataSourcePrototype[DicomTags.Units] = _frames[0].Sop.DataSource[DicomTags.Units].Copy(); // PET series use this attribute to designate rescale units // compute normalized VOI windows VoiWindow.SetWindows(ComputeNormalizedVoiWindows(_frames, normalizedSlope, normalizedIntercept), sopDataSourcePrototype); // compute the volume padding value var pixelPaddingValue = ComputePixelPaddingValue(_frames, normalizedSlope, normalizedIntercept); int minVolumeValue, maxVolumeValue; var volumeArray = BuildVolumeArray(pixelPaddingValue, normalizedSlope, normalizedIntercept, out minVolumeValue, out maxVolumeValue); var volume = new Volume(null, volumeArray, VolumeSize, VoxelSpacing, ImagePositionPatient, ImageOrientationPatient, sopDataSourcePrototype, pixelPaddingValue, _frames[0].Frame.SeriesInstanceUid, minVolumeValue, maxVolumeValue); return(volume); }
private Volume(short[] dataInt16, ushort[] dataUInt16, Size3D dimensions, Vector3D spacing, Vector3D originPatient, Matrix orientationPatient, VolumeSopDataSourcePrototype sopDataSourcePrototype, int paddingValue, string sourceSeriesInstanceUid, int minVolumeValue, int maxVolumeValue) { Platform.CheckTrue(dataInt16 != null ^ dataUInt16 != null, "Exactly one of dataInt16 and dataUInt16 must be non-null."); _volumeDataInt16 = dataInt16; _volumeDataUInt16 = dataUInt16; _sourceSeriesInstanceUid = sourceSeriesInstanceUid; _minVolumeValue = minVolumeValue; _maxVolumeValue = maxVolumeValue; _arrayDimensions = dimensions; _voxelSpacing = spacing; _originPatient = originPatient; _orientationPatientMatrix = orientationPatient; _modelDicom = sopDataSourcePrototype; _paddingValue = paddingValue; // Generate a descriptive name for the volume PersonName patientName = new PersonName(sopDataSourcePrototype[DicomTags.PatientsName].ToString()); string patientId = sopDataSourcePrototype[DicomTags.PatientId].ToString(); string seriesDescription = sopDataSourcePrototype[DicomTags.SeriesDescription].ToString(); if (string.IsNullOrEmpty(seriesDescription)) { _description = string.Format(SR.FormatVolumeLabel, patientName.FormattedName, patientId, seriesDescription); } else { _description = string.Format(SR.FormatVolumeLabelWithSeries, patientName.FormattedName, patientId, seriesDescription); } }
public static VolumeSopDataSourcePrototype Create(IDicomAttributeProvider source, int bitsAllocated, int bitsStored, bool isSigned) { VolumeSopDataSourcePrototype prototype = new VolumeSopDataSourcePrototype(); DicomAttributeCollection volumeDataSet = prototype._collection; // perform exact copy on the Patient Module foreach (uint tag in PatientModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the Clinical Trial Subject Module foreach (uint tag in ClinicalTrialSubjectModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the General Study Module foreach (uint tag in GeneralStudyModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the Patient Study Module foreach (uint tag in PatientStudyModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the Clinical Trial Study Module foreach (uint tag in ClinicalTrialStudyModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // TODO JY: flesh out these other modules. // generate and cache Series Module attributes that are common among all slicings volumeDataSet[DicomTags.Modality] = source[DicomTags.Modality].Copy(); volumeDataSet[DicomTags.SeriesNumber].SetStringValue("0"); volumeDataSet[DicomTags.SeriesDescription] = source[DicomTags.SeriesDescription].Copy(); // generate General Equipment Module // these is a ticket to properly implement the GenEq module in all created instances. // the ticket is specific to KO and PR, but it should equally apply to these MPR SCs // generate SC Equipment Module volumeDataSet[DicomTags.ConversionType].SetStringValue("WSD"); // generate General Image Module volumeDataSet[DicomTags.ImageType].SetStringValue(@"DERIVED\SECONDARY"); volumeDataSet[DicomTags.PixelSpacing] = source[DicomTags.PixelSpacing].Copy(); volumeDataSet[DicomTags.FrameOfReferenceUid] = source[DicomTags.FrameOfReferenceUid].Copy(); // generate Image Pixel Module volumeDataSet[DicomTags.SamplesPerPixel] = source[DicomTags.SamplesPerPixel].Copy(); volumeDataSet[DicomTags.PhotometricInterpretation] = source[DicomTags.PhotometricInterpretation].Copy(); volumeDataSet[DicomTags.BitsAllocated].SetInt32(0, bitsAllocated); volumeDataSet[DicomTags.BitsStored].SetInt32(0, bitsStored); volumeDataSet[DicomTags.HighBit].SetInt32(0, bitsStored - 1); volumeDataSet[DicomTags.PixelRepresentation].SetInt32(0, isSigned ? 1 : 0); // generate SOP Common Module volumeDataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid); return prototype; }
/// <summary> /// Constructs a <see cref="Volume"/> using a volume data array of unsigned 16-bit words. /// </summary> /// <remarks> /// Consider using one of the static helpers such as <see cref="Create(ClearCanvas.ImageViewer.IDisplaySet)"/> to construct and automatically fill a <see cref="Volume"/>. /// </remarks> public Volume(ushort[] data, Size3D dimensions, Vector3D spacing, Vector3D originPatient, Matrix orientationPatient, IList <IDicomAttributeProvider> dicomAttributeModel, int paddingValue, string sourceSeriesInstanceUid) : this(null, data, dimensions, spacing, originPatient, orientationPatient, VolumeSopDataSourcePrototype.Create(dicomAttributeModel, 16, 16, false), paddingValue, sourceSeriesInstanceUid, 0, 0) { }
public static VolumeSopDataSourcePrototype Create(IList <IDicomAttributeProvider> sourceSops, int bitsAllocated, int bitsStored, bool isSigned) { const string enumYes = "YES"; const string enumNo = "NO"; const string enumLossy = "01"; const string enumLossless = "00"; VolumeSopDataSourcePrototype prototype = new VolumeSopDataSourcePrototype(); DicomAttributeCollection volumeDataSet = prototype._collection; IDicomAttributeProvider source = sourceSops[0]; // perform exact copy on the Patient Module foreach (uint tag in PatientModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the Clinical Trial Subject Module foreach (uint tag in ClinicalTrialSubjectModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the General Study Module foreach (uint tag in GeneralStudyModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the Patient Study Module foreach (uint tag in PatientStudyModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the Clinical Trial Study Module foreach (uint tag in ClinicalTrialStudyModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the General Series Module except for tags that will be overridden as part of reformatting foreach (uint tag in GeneralSeriesModuleIod.DefinedTags.Except(new[] { DicomTags.LargestPixelValueInSeries, DicomTags.SmallestPixelValueInSeries, DicomTags.SeriesInstanceUid })) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the Clinical Trial Series Module foreach (uint tag in ClinicalTrialSeriesModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on additional modality specific modules in the series IE foreach (uint tag in ModalitySpecificSeriesModuleTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the General Equipment Module foreach (uint tag in GeneralEquipmentModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // generate values for SC Equipment Module var scEquipment = new ScEquipmentModuleIod(volumeDataSet); scEquipment.ConversionType = @"WSD"; scEquipment.SecondaryCaptureDeviceManufacturer = @"ClearCanvas Inc."; scEquipment.SecondaryCaptureDeviceManufacturersModelName = ProductInformation.GetName(true, false); scEquipment.SecondaryCaptureDeviceSoftwareVersions = new[] { ProductInformation.GetVersion(true, true, true) }; // fill series-consistent values for the Frame of Reference Module volumeDataSet[DicomTags.FrameOfReferenceUid] = source[DicomTags.FrameOfReferenceUid].Copy(); // generate values for the General Image Module var burnedInAnnotationValues = sourceSops.Select(s => s[DicomTags.BurnedInAnnotation].GetBoolean(0, enumYes, enumNo)).ToList(); var burnedInAnnotation = burnedInAnnotationValues.Any(v => v.GetValueOrDefault(false)) ? true : (burnedInAnnotationValues.All(v => !v.GetValueOrDefault(true)) ? false : (bool?)null); var recognizableVisualFeaturesValues = sourceSops.Select(s => s[DicomTags.RecognizableVisualFeatures].GetBoolean(0, enumYes, enumNo)).ToList(); var recognizableVisualFeatures = recognizableVisualFeaturesValues.Any(v => v.GetValueOrDefault(false)) ? true : (recognizableVisualFeaturesValues.All(v => !v.GetValueOrDefault(true)) ? false : (bool?)null); var lossyImageCompressionValues = sourceSops.Select(s => s[DicomTags.LossyImageCompression].GetBoolean(0, enumLossy, enumLossless)).ToList(); var lossyImageCompression = lossyImageCompressionValues.Any(v => v.GetValueOrDefault(false)) ? true : (lossyImageCompressionValues.All(v => !v.GetValueOrDefault(true)) ? false : (bool?)null); var lossyImageCompressionRatioValues = sourceSops.Select(s => s[DicomTags.LossyImageCompressionRatio].GetFloat32(0, 0)).ToList(); var lossyImageCompressionRatio = lossyImageCompressionRatioValues.Max(); volumeDataSet[DicomTags.ImageType].SetStringValue(@"DERIVED\SECONDARY"); volumeDataSet[DicomTags.DerivationDescription].SetStringValue(@"Multiplanar Reformatting"); volumeDataSet[DicomTags.DerivationCodeSequence].Values = new[] { new CodeSequenceMacro { CodingSchemeDesignator = "DCM", CodeValue = "113072", CodeMeaning = "Multiplanar reformatting" }.DicomSequenceItem }; volumeDataSet[DicomTags.BurnedInAnnotation].SetBoolean(0, burnedInAnnotation, enumYes, enumNo); volumeDataSet[DicomTags.RecognizableVisualFeatures].SetBoolean(0, recognizableVisualFeatures, enumYes, enumNo); volumeDataSet[DicomTags.LossyImageCompression].SetBoolean(0, lossyImageCompression, enumLossy, enumLossless); if (lossyImageCompressionRatio > 0) { volumeDataSet[DicomTags.LossyImageCompressionRatio].SetFloat32(0, lossyImageCompressionRatio); } // TODO: there's a SourceImageSequence here that we should probably fill out // fill series-consistent values for the Image Plane Module volumeDataSet[DicomTags.PixelSpacing] = source[DicomTags.PixelSpacing].Copy(); // fill series-consistent values for the Image Pixel Module volumeDataSet[DicomTags.SamplesPerPixel] = source[DicomTags.SamplesPerPixel].Copy(); volumeDataSet[DicomTags.PhotometricInterpretation] = source[DicomTags.PhotometricInterpretation].Copy(); volumeDataSet[DicomTags.BitsAllocated].SetInt32(0, bitsAllocated); volumeDataSet[DicomTags.BitsStored].SetInt32(0, bitsStored); volumeDataSet[DicomTags.HighBit].SetInt32(0, bitsStored - 1); volumeDataSet[DicomTags.PixelRepresentation].SetInt32(0, isSigned ? 1 : 0); // fill series-consistent values for the SOP Common Module volumeDataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid); return(prototype); }
internal static IDicomAttributeProvider TestCreateSopDataSourcePrototype(IList <IDicomAttributeProvider> sourceSops, int bitsAllocated = 16, int bitsStored = 16, bool isSigned = false) { return(VolumeSopDataSourcePrototype.Create(sourceSops, bitsAllocated, bitsStored, isSigned)); }
private Volume(short[] dataInt16, ushort[] dataUInt16, Size3D dimensions, Vector3D spacing, Vector3D originPatient, Matrix orientationPatient, VolumeSopDataSourcePrototype sopDataSourcePrototype, int paddingValue, string sourceSeriesInstanceUid, int minVolumeValue, int maxVolumeValue) { Platform.CheckTrue(dataInt16 != null ^ dataUInt16 != null, "Exactly one of dataInt16 and dataUInt16 must be non-null."); _volumeDataInt16 = dataInt16; _volumeDataUInt16 = dataUInt16; _sourceSeriesInstanceUid = sourceSeriesInstanceUid; _minVolumeValue = minVolumeValue; _maxVolumeValue = maxVolumeValue; _arrayDimensions = dimensions; _voxelSpacing = spacing; _originPatient = originPatient; _orientationPatientMatrix = orientationPatient; _modelDicom = sopDataSourcePrototype; _paddingValue = paddingValue; // Generate a descriptive name for the volume PersonName patientName = new PersonName(sopDataSourcePrototype[DicomTags.PatientsName].ToString()); string patientId = sopDataSourcePrototype[DicomTags.PatientId].ToString(); string seriesDescription = sopDataSourcePrototype[DicomTags.SeriesDescription].ToString(); if (string.IsNullOrEmpty(seriesDescription)) _description = string.Format(SR.FormatVolumeLabel, patientName.FormattedName, patientId, seriesDescription); else _description = string.Format(SR.FormatVolumeLabelWithSeries, patientName.FormattedName, patientId, seriesDescription); }
public static VolumeSopDataSourcePrototype Create(IList<IDicomAttributeProvider> sourceSops, int bitsAllocated, int bitsStored, bool isSigned) { const string enumYes = "YES"; const string enumNo = "NO"; const string enumLossy = "01"; const string enumLossless = "00"; VolumeSopDataSourcePrototype prototype = new VolumeSopDataSourcePrototype(); DicomAttributeCollection volumeDataSet = prototype._collection; IDicomAttributeProvider source = sourceSops[0]; // perform exact copy on the Patient Module foreach (uint tag in PatientModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the Clinical Trial Subject Module foreach (uint tag in ClinicalTrialSubjectModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the General Study Module foreach (uint tag in GeneralStudyModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the Patient Study Module foreach (uint tag in PatientStudyModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the Clinical Trial Study Module foreach (uint tag in ClinicalTrialStudyModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the General Series Module except for tags that will be overridden as part of reformatting foreach (uint tag in GeneralSeriesModuleIod.DefinedTags.Except(new[] {DicomTags.LargestPixelValueInSeries, DicomTags.SmallestPixelValueInSeries, DicomTags.SeriesInstanceUid})) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the Clinical Trial Series Module foreach (uint tag in ClinicalTrialSeriesModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on additional modality specific modules in the series IE foreach (uint tag in ModalitySpecificSeriesModuleTags) volumeDataSet[tag] = source[tag].Copy(); // perform exact copy on the General Equipment Module foreach (uint tag in GeneralEquipmentModuleIod.DefinedTags) volumeDataSet[tag] = source[tag].Copy(); // generate values for SC Equipment Module var scEquipment = new ScEquipmentModuleIod(volumeDataSet); scEquipment.ConversionType = @"WSD"; scEquipment.SecondaryCaptureDeviceManufacturer = @"ClearCanvas Inc."; scEquipment.SecondaryCaptureDeviceManufacturersModelName = ProductInformation.GetName(true, false); scEquipment.SecondaryCaptureDeviceSoftwareVersions = new[] {ProductInformation.GetVersion(true, true, true)}; // fill series-consistent values for the Frame of Reference Module volumeDataSet[DicomTags.FrameOfReferenceUid] = source[DicomTags.FrameOfReferenceUid].Copy(); // generate values for the General Image Module var burnedInAnnotationValues = sourceSops.Select(s => s[DicomTags.BurnedInAnnotation].GetBoolean(0, enumYes, enumNo)).ToList(); var burnedInAnnotation = burnedInAnnotationValues.Any(v => v.GetValueOrDefault(false)) ? true : (burnedInAnnotationValues.All(v => !v.GetValueOrDefault(true)) ? false : (bool?) null); var recognizableVisualFeaturesValues = sourceSops.Select(s => s[DicomTags.RecognizableVisualFeatures].GetBoolean(0, enumYes, enumNo)).ToList(); var recognizableVisualFeatures = recognizableVisualFeaturesValues.Any(v => v.GetValueOrDefault(false)) ? true : (recognizableVisualFeaturesValues.All(v => !v.GetValueOrDefault(true)) ? false : (bool?) null); var lossyImageCompressionValues = sourceSops.Select(s => s[DicomTags.LossyImageCompression].GetBoolean(0, enumLossy, enumLossless)).ToList(); var lossyImageCompression = lossyImageCompressionValues.Any(v => v.GetValueOrDefault(false)) ? true : (lossyImageCompressionValues.All(v => !v.GetValueOrDefault(true)) ? false : (bool?) null); var lossyImageCompressionRatioValues = sourceSops.Select(s => s[DicomTags.LossyImageCompressionRatio].GetFloat32(0, 0)).ToList(); var lossyImageCompressionRatio = lossyImageCompressionRatioValues.Max(); volumeDataSet[DicomTags.ImageType].SetStringValue(@"DERIVED\SECONDARY"); volumeDataSet[DicomTags.DerivationDescription].SetStringValue(@"Multiplanar Reformatting"); volumeDataSet[DicomTags.DerivationCodeSequence].Values = new[] {new CodeSequenceMacro {CodingSchemeDesignator = "DCM", CodeValue = "113072", CodeMeaning = "Multiplanar reformatting"}.DicomSequenceItem}; volumeDataSet[DicomTags.BurnedInAnnotation].SetBoolean(0, burnedInAnnotation, enumYes, enumNo); volumeDataSet[DicomTags.RecognizableVisualFeatures].SetBoolean(0, recognizableVisualFeatures, enumYes, enumNo); volumeDataSet[DicomTags.LossyImageCompression].SetBoolean(0, lossyImageCompression, enumLossy, enumLossless); if (lossyImageCompressionRatio > 0) volumeDataSet[DicomTags.LossyImageCompressionRatio].SetFloat32(0, lossyImageCompressionRatio); // TODO: there's a SourceImageSequence here that we should probably fill out // fill series-consistent values for the Image Plane Module volumeDataSet[DicomTags.PixelSpacing] = source[DicomTags.PixelSpacing].Copy(); // fill series-consistent values for the Image Pixel Module volumeDataSet[DicomTags.SamplesPerPixel] = source[DicomTags.SamplesPerPixel].Copy(); volumeDataSet[DicomTags.PhotometricInterpretation] = source[DicomTags.PhotometricInterpretation].Copy(); volumeDataSet[DicomTags.BitsAllocated].SetInt32(0, bitsAllocated); volumeDataSet[DicomTags.BitsStored].SetInt32(0, bitsStored); volumeDataSet[DicomTags.HighBit].SetInt32(0, bitsStored - 1); volumeDataSet[DicomTags.PixelRepresentation].SetInt32(0, isSigned ? 1 : 0); // fill series-consistent values for the SOP Common Module volumeDataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid); return prototype; }
public static VolumeSopDataSourcePrototype Create(IDicomAttributeProvider source, int bitsAllocated, int bitsStored, bool isSigned) { VolumeSopDataSourcePrototype prototype = new VolumeSopDataSourcePrototype(); DicomAttributeCollection volumeDataSet = prototype._collection; // perform exact copy on the Patient Module foreach (uint tag in PatientModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the Clinical Trial Subject Module foreach (uint tag in ClinicalTrialSubjectModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the General Study Module foreach (uint tag in GeneralStudyModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the Patient Study Module foreach (uint tag in PatientStudyModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // perform exact copy on the Clinical Trial Study Module foreach (uint tag in ClinicalTrialStudyModuleIod.DefinedTags) { volumeDataSet[tag] = source[tag].Copy(); } // TODO JY: flesh out these other modules. // generate and cache Series Module attributes that are common among all slicings volumeDataSet[DicomTags.Modality] = source[DicomTags.Modality].Copy(); volumeDataSet[DicomTags.SeriesNumber].SetStringValue("0"); volumeDataSet[DicomTags.SeriesDescription] = source[DicomTags.SeriesDescription].Copy(); // generate General Equipment Module // these is a ticket to properly implement the GenEq module in all created instances. // the ticket is specific to KO and PR, but it should equally apply to these MPR SCs // generate SC Equipment Module volumeDataSet[DicomTags.ConversionType].SetStringValue("WSD"); // generate General Image Module volumeDataSet[DicomTags.ImageType].SetStringValue(@"DERIVED\SECONDARY"); volumeDataSet[DicomTags.PixelSpacing] = source[DicomTags.PixelSpacing].Copy(); volumeDataSet[DicomTags.FrameOfReferenceUid] = source[DicomTags.FrameOfReferenceUid].Copy(); // generate Image Pixel Module volumeDataSet[DicomTags.SamplesPerPixel] = source[DicomTags.SamplesPerPixel].Copy(); volumeDataSet[DicomTags.PhotometricInterpretation] = source[DicomTags.PhotometricInterpretation].Copy(); volumeDataSet[DicomTags.BitsAllocated].SetInt32(0, bitsAllocated); volumeDataSet[DicomTags.BitsStored].SetInt32(0, bitsStored); volumeDataSet[DicomTags.HighBit].SetInt32(0, bitsStored - 1); volumeDataSet[DicomTags.PixelRepresentation].SetInt32(0, isSigned ? 1 : 0); // generate SOP Common Module volumeDataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid); return(prototype); }