internal static void FillDataSet(IDicomAttributeProvider dataSet, VolumeSlice slice) { // generate values for SC Equipment Module var scEquipment = new ScEquipmentModuleIod(dataSet); scEquipment.ConversionType = @"WSD"; scEquipment.SecondaryCaptureDeviceManufacturer = @"ClearCanvas Inc."; scEquipment.SecondaryCaptureDeviceManufacturersModelName = ProductInformation.GetName(false, false); scEquipment.SecondaryCaptureDeviceSoftwareVersions = new[] { ProductInformation.GetVersion(true, true, true, true) }; // generate values for the General Image Module dataSet[DicomTags.ImageType].SetStringValue(@"DERIVED\SECONDARY"); dataSet[DicomTags.DerivationDescription].SetStringValue(@"Multiplanar Reformatting"); dataSet[DicomTags.DerivationCodeSequence].Values = new[] { ImageDerivationContextGroup.MultiplanarReformatting.AsDicomSequenceItem() }; // update the Image Plane Module dataSet[DicomTags.PixelSpacing].SetStringValue(slice.PixelSpacing); dataSet[DicomTags.ImageOrientationPatient].SetStringValue(slice.ImageOrientationPatient); dataSet[DicomTags.ImagePositionPatient].SetStringValue(slice.ImagePositionPatient); dataSet[DicomTags.SliceThickness].SetStringValue(slice.SliceThickness); // update the spacing between slices, even though it's only part of modality-specific modules dataSet[DicomTags.SpacingBetweenSlices].SetStringValue(slice.SpacingBetweenSlices); // update the Image Pixel Module dataSet[DicomTags.Rows].SetInt32(0, slice.Rows); dataSet[DicomTags.Columns].SetInt32(0, slice.Columns); // generate values for Multi-Frame Module dataSet[DicomTags.NumberOfFrames].SetInt32(0, 1); // generate values for SOP Common Module dataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid); dataSet[DicomTags.SopInstanceUid].SetStringValue(DicomUid.GenerateUid().UID); }
/// <summary> /// Initializes a new <see cref="ISopDataSource"/> for the given volume slice. /// </summary> /// <param name="slice">A volume slice. This instance will be disposed when the <see cref="VolumeSliceSopDataSource"/> instance is disposed.</param> public VolumeSliceSopDataSource(VolumeSlice slice) { Slice = slice; DataSet = new DicomAttributeCollection() { ValidateVrLengths = false, ValidateVrValues = false }; FillDataSet(DataSet, slice); }
/// <summary> /// Initializes a new <see cref="ISopDataSource"/> for the given volume slice. /// </summary> /// <param name="slice">A volume slice. This instance will be disposed when the <see cref="VolumeSliceSopDataSource"/> instance is disposed.</param> public AsyncVolumeSliceSopDataSource(VolumeSlice slice) { Slice = slice; DataSet = new DicomAttributeCollection(); DataSet[DicomTags.Rows].SetInt32(0, Slice.Rows); DataSet[DicomTags.Columns].SetInt32(0, Slice.Colums); DataSet[DicomTags.NumberOfFrames].SetInt32(0, 1); DataSet[DicomTags.ImageOrientationPatient].SetStringValue(Slice.ImageOrientationPatient); DataSet[DicomTags.ImagePositionPatient].SetStringValue(Slice.ImagePositionPatient); DataSet[DicomTags.SopInstanceUid].SetString(0, DicomUid.GenerateUid().UID); }
/// <summary> /// Initializes a new <see cref="ISopDataSource"/> for the given volume slice. /// </summary> /// <param name="slice">A volume slice. This instance will be disposed when the <see cref="VolumeSliceSopDataSource"/> instance is disposed.</param> public VolumeSliceSopDataSource(VolumeSlice slice) { Slice = slice; DataSet = new DicomAttributeCollection(); DataSet[DicomTags.Rows].SetInt32(0, Slice.Rows); DataSet[DicomTags.Columns].SetInt32(0, Slice.Colums); DataSet[DicomTags.NumberOfFrames].SetInt32(0, 1); DataSet[DicomTags.ImageOrientationPatient].SetStringValue(Slice.ImageOrientationPatient); DataSet[DicomTags.ImagePositionPatient].SetStringValue(Slice.ImagePositionPatient); DataSet[DicomTags.SopInstanceUid].SetString(0, DicomUid.GenerateUid().UID); }
public IEnumerable<VolumeSlice> CreateSlices() { // get the slice spacing in voxel units var sliceSpacing = GetSliceSpacing(); // get the normal to the plane of slicing (the plane of slicing is the XY plane in the slicing coordinate frame) var slicePlaneNormal = GetSliceNormalVector(); // get a point through which the slices should pass var sliceThroughPoint = GetSliceThroughPoint(); // compute the number of slices required in this slicing rotation, and the slice location at which to start int sliceCount; float startingSliceLocation; { // the algorithm for this involves computing the bounding cube for the volume *in the slicing coordinate frame* // the number of required slices is thus the span of the Z components (i.e. slice location) of the bounding cube, divided by the slice spacing // this algorithm reduces to determining the projection of each of the 8 corners of the volume onto the normal vector of the slice plane var minSliceLocation = float.MaxValue; var maxSliceLocation = float.MinValue; var volumeDimensions = _volume.Volume.Dimensions; foreach (var corner in new[] { new Vector3D(0, 0, 0), new Vector3D(volumeDimensions.X, 0, 0), new Vector3D(0, volumeDimensions.Y, 0), new Vector3D(0, 0, volumeDimensions.Z), new Vector3D(volumeDimensions.X, volumeDimensions.Y, 0), new Vector3D(volumeDimensions.X, 0, volumeDimensions.Z), new Vector3D(0, volumeDimensions.Y, volumeDimensions.Z), new Vector3D(volumeDimensions.X, volumeDimensions.Y, volumeDimensions.Z) }) { // project the corner vector onto the slice plane normal vector var zCoord = slicePlaneNormal.Dot(corner); minSliceLocation = Math.Min(minSliceLocation, zCoord); maxSliceLocation = Math.Max(maxSliceLocation, zCoord); } // divide the span of the slice locations by the slice spacing to determine the required number of slices sliceCount = (int) Math.Ceiling((maxSliceLocation - minSliceLocation)/sliceSpacing); // the starting slice location could be either end, but we choose the larger end to be consistent with the original implementation startingSliceLocation = maxSliceLocation; } // compute the incremental spacing vector var spacingVector = sliceSpacing*slicePlaneNormal; // compute the slice location of the specified through point var throughPointSliceLocation = slicePlaneNormal.Dot(sliceThroughPoint); // compute the through point of the first slice // (subtract an extra spacing vector, because we're computing from the larger end of the volume voxels, while VTK draws slices from the smaller end of the voxels. var initialThroughPoint = sliceThroughPoint + (startingSliceLocation - throughPointSliceLocation)/sliceSpacing*spacingVector - spacingVector; var thicknessAndSpacing = Math.Abs(GetSliceSpacing()); // generate the slice SOPs by computing additional through points for (var n = 0; n < sliceCount; n++) { var slice = new VolumeSlice(_volume.Clone(), _slicerParams, initialThroughPoint - n*spacingVector); slice[DicomTags.SliceThickness].SetFloat32(0, thicknessAndSpacing); slice[DicomTags.SpacingBetweenSlices].SetFloat32(0, thicknessAndSpacing); yield return slice; } }
public IEnumerable <VolumeSlice> CreateSlices() { // get the slice spacing in voxel units var sliceSpacing = GetSliceSpacing(); // get the normal to the plane of slicing (the plane of slicing is the XY plane in the slicing coordinate frame) var slicePlaneNormal = GetSliceNormalVector(); // get a point through which the slices should pass var sliceThroughPoint = GetSliceThroughPoint(); // compute the number of slices required in this slicing rotation, and the slice location at which to start int sliceCount; float startingSliceLocation; { // the algorithm for this involves computing the bounding cube for the volume *in the slicing coordinate frame* // the number of required slices is thus the span of the Z components (i.e. slice location) of the bounding cube, divided by the slice spacing // this algorithm reduces to determining the projection of each of the 8 corners of the volume onto the normal vector of the slice plane var minSliceLocation = float.MaxValue; var maxSliceLocation = float.MinValue; var volumeDimensions = _volume.Volume.Dimensions; foreach (var corner in new[] { new Vector3D(0, 0, 0), new Vector3D(volumeDimensions.X, 0, 0), new Vector3D(0, volumeDimensions.Y, 0), new Vector3D(0, 0, volumeDimensions.Z), new Vector3D(volumeDimensions.X, volumeDimensions.Y, 0), new Vector3D(volumeDimensions.X, 0, volumeDimensions.Z), new Vector3D(0, volumeDimensions.Y, volumeDimensions.Z), new Vector3D(volumeDimensions.X, volumeDimensions.Y, volumeDimensions.Z) }) { // project the corner vector onto the slice plane normal vector var zCoord = slicePlaneNormal.Dot(corner); minSliceLocation = Math.Min(minSliceLocation, zCoord); maxSliceLocation = Math.Max(maxSliceLocation, zCoord); } // divide the span of the slice locations by the slice spacing to determine the required number of slices sliceCount = (int)Math.Ceiling((maxSliceLocation - minSliceLocation) / sliceSpacing); // the starting slice location could be either end, but we choose the larger end to be consistent with the original implementation startingSliceLocation = maxSliceLocation; } // compute the incremental spacing vector var spacingVector = sliceSpacing * slicePlaneNormal; // compute the slice location of the specified through point var throughPointSliceLocation = slicePlaneNormal.Dot(sliceThroughPoint); // compute the through point of the first slice // (subtract an extra spacing vector, because we're computing from the larger end of the volume voxels, while VTK draws slices from the smaller end of the voxels. var initialThroughPoint = sliceThroughPoint + (startingSliceLocation - throughPointSliceLocation) / sliceSpacing * spacingVector - spacingVector; var thicknessAndSpacing = Math.Abs(GetSliceSpacing()); // generate the slice SOPs by computing additional through points for (var n = 0; n < sliceCount; n++) { var slice = new VolumeSlice(_volume.Clone(), _slicerParams, initialThroughPoint - n * spacingVector); slice[DicomTags.SliceThickness].SetFloat32(0, thicknessAndSpacing); slice[DicomTags.SpacingBetweenSlices].SetFloat32(0, thicknessAndSpacing); yield return(slice); } }
/// <summary> /// Initializes a new <see cref="ISopDataSource"/> for the given volume slice. /// </summary> /// <param name="slice">A volume slice. This instance will be disposed when the <see cref="VolumeSliceSopDataSource"/> instance is disposed.</param> public VolumeSliceSopDataSource(VolumeSlice slice) { Slice = slice; DataSet = new DicomAttributeCollection(); FillDataSet(DataSet, slice); }