/// <summary> /// Initializes the instance of <see cref="VolumeSlicerCore"/>. /// </summary> /// <param name="volumeReference">The <see cref="IVolumeReference"/> of the volume.</param> /// <param name="args">The requested slicer algorithm parameters.</param> /// <exception cref="ArgumentNullException">Thrown if either <paramref name="volumeReference"/> or <paramref name="args"/> are null.</exception> protected VolumeSlicerCore(IVolumeReference volumeReference, VolumeSliceArgs args) { Platform.CheckForNullReference(volumeReference, "volume"); Platform.CheckForNullReference(args, "args"); _volumeReference = volumeReference; _args = args; }
internal VolumeSlice(IVolumeReference volumeReference, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float?spacingBetweenSlices) { Platform.CheckForNullReference(volumeReference, "volumeReference"); Platform.CheckForNullReference(sliceArgs, "slicerArgs"); Platform.CheckForNullReference(imagePositionPatient, "imagePositionPatient"); _volumeReference = volumeReference; _sliceArgs = sliceArgs; _imagePositionPatient = imagePositionPatient; // compute Rows and Columns to reflect actual output size Columns = sliceArgs.Columns; Rows = sliceArgs.Rows; // compute Slice Thickness var sliceThickness = sliceArgs.SliceThickness; SliceThickness = new DicomAttributeDS(DicomTags.SliceThickness) { Values = sliceThickness }.ToString(); SpacingBetweenSlices = spacingBetweenSlices.HasValue ? new DicomAttributeDS(DicomTags.SpacingBetweenSlices) { Values = spacingBetweenSlices.Value }.ToString() : string.Empty; // compute Pixel Spacing var spacing = new DicomAttributeDS(DicomTags.PixelSpacing); spacing.SetFloat32(0, sliceArgs.RowSpacing); spacing.SetFloat32(1, sliceArgs.ColumnSpacing); PixelSpacing = spacing.ToString(); // compute Image Orientation (Patient) var rowOrientation = sliceArgs.RowOrientationPatient; var columnOrientation = sliceArgs.ColumnOrientationPatient; var orientation = new DicomAttributeDS(DicomTags.ImageOrientationPatient); orientation.SetFloat32(0, rowOrientation.X); orientation.SetFloat32(1, rowOrientation.Y); orientation.SetFloat32(2, rowOrientation.Z); orientation.SetFloat32(3, columnOrientation.X); orientation.SetFloat32(4, columnOrientation.Y); orientation.SetFloat32(5, columnOrientation.Z); ImageOrientationPatient = orientation.ToString(); // compute Image Position (Patient) var position = new DicomAttributeDS(DicomTags.ImagePositionPatient); position.SetFloat32(0, _imagePositionPatient.X); position.SetFloat32(1, _imagePositionPatient.Y); position.SetFloat32(2, _imagePositionPatient.Z); ImagePositionPatient = position.ToString(); }
protected virtual void Dispose(bool disposing) { if (!disposing) { return; } if (_volumeReference != null) { _volumeReference.Dispose(); _volumeReference = null; } _sliceArgs = null; _imagePositionPatient = null; }
/// <summary> /// Creates an implementation of <see cref="IVolumeSlicerCore"/> for slicing the requested volume. /// </summary> /// <param name="volumeReference">Reference to the <see cref="Volume"/> to be resliced.</param> /// <param name="args">The requested reslicing parameters.</param> public static IVolumeSlicerCore Create(IVolumeReference volumeReference, VolumeSliceArgs args) { if (_coreProviders == null) { try { _coreProviders = new VolumeSlicerCoreProviderExtensionPoint().CreateExtensions().Cast <IVolumeSlicerCoreProvider>().ToList(); } catch (Exception ex) { Platform.Log(LogLevel.Error, ex, "Failed to initialize implementations on VolumeSlicerCoreProviderExtensionPoint"); } } if (_coreProviders == null || !_coreProviders.Any()) { #if UNIT_TESTS // ensures the VTK version is loaded if possible TypeRef.Get("ClearCanvas.ImageViewer.Vtk.VtkVolumeSlicerCoreProvider, ClearCanvas.ImageViewer.VTK").Resolve(); // ensures that unit tests running under a custom extension factory will always have a slicer implementation where available _coreProviders = Platform.PluginManager.ExtensionPoints .First(e => e.ExtensionPointClass == typeof(VolumeSlicerCoreProviderExtensionPoint)) .ListExtensions().Select(x => Activator.CreateInstance(x.ExtensionClass.Resolve())) .Cast <IVolumeSlicerCoreProvider>().ToList(); if (_coreProviders == null || !_coreProviders.Any()) { throw new NotSupportedException("No implementations of IVolumeSlicerCoreProvider were found."); } #else throw new NotSupportedException("No implementations of IVolumeSlicerCoreProvider were found."); #endif } try { return(_coreProviders.First(c => c.IsSupported(args)).CreateSlicerCore(volumeReference, args)); } catch (Exception ex) { throw new NotSupportedException("No suitable implementation of IVolumeSlicerCoreProvider was found.", ex); } }
internal VolumeSlice(IVolumeReference volumeReference, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float? spacingBetweenSlices) { Platform.CheckForNullReference(volumeReference, "volumeReference"); Platform.CheckForNullReference(sliceArgs, "slicerArgs"); Platform.CheckForNullReference(imagePositionPatient, "imagePositionPatient"); _volumeReference = volumeReference; _sliceArgs = sliceArgs; _imagePositionPatient = imagePositionPatient; // compute Rows and Columns to reflect actual output size Columns = sliceArgs.Columns; Rows = sliceArgs.Rows; // compute Slice Thickness var sliceThickness = sliceArgs.SliceThickness; SliceThickness = new DicomAttributeDS(DicomTags.SliceThickness) {Values = sliceThickness}.ToString(); SpacingBetweenSlices = spacingBetweenSlices.HasValue ? new DicomAttributeDS(DicomTags.SpacingBetweenSlices) {Values = spacingBetweenSlices.Value}.ToString() : string.Empty; // compute Pixel Spacing var spacing = new DicomAttributeDS(DicomTags.PixelSpacing); spacing.SetFloat32(0, sliceArgs.RowSpacing); spacing.SetFloat32(1, sliceArgs.ColumnSpacing); PixelSpacing = spacing.ToString(); // compute Image Orientation (Patient) var rowOrientation = sliceArgs.RowOrientationPatient; var columnOrientation = sliceArgs.ColumnOrientationPatient; var orientation = new DicomAttributeDS(DicomTags.ImageOrientationPatient); orientation.SetFloat32(0, rowOrientation.X); orientation.SetFloat32(1, rowOrientation.Y); orientation.SetFloat32(2, rowOrientation.Z); orientation.SetFloat32(3, columnOrientation.X); orientation.SetFloat32(4, columnOrientation.Y); orientation.SetFloat32(5, columnOrientation.Z); ImageOrientationPatient = orientation.ToString(); // compute Image Position (Patient) var position = new DicomAttributeDS(DicomTags.ImagePositionPatient); position.SetFloat32(0, _imagePositionPatient.X); position.SetFloat32(1, _imagePositionPatient.Y); position.SetFloat32(2, _imagePositionPatient.Z); ImagePositionPatient = position.ToString(); }
public bool IsSupported(VolumeSliceArgs args) { return true; }
private IEnumerable <VolumeSlice> CreateSlicesCore(IVolumeReference volumeReference, Vector3D startPosition, Vector3D endPosition, int count) { // get the axes of the output plane and its normal in patient coordinates - these are the axes of the slicer frame var slicerAxisX = (RowOrientationPatient ?? volumeReference.VolumeOrientationPatientX).Normalize(); var slicerAxisY = (ColumnOrientationPatient ?? volumeReference.VolumeOrientationPatientY).Normalize(); var slicerAxisZ = (StackOrientationPatient ?? slicerAxisX.Cross(slicerAxisY)).Normalize(); // get the pixel spacing (defaults to isotropic spacing based on smallest volume spacing dimension) var pixelSpacing = GetPixelSpacing(volumeReference); // get the spacing between slices (defaults to smallest volume spacing dimension) var sliceSpacing = GetSliceSpacing(volumeReference, slicerAxisZ); // get the thickness of each slice (defaults to slice spacing) var sliceThickness = SliceThickness ?? sliceSpacing; // get the ideal subsampling for the slice thickness var sliceSubsamples = Math.Max(1, (int)(sliceThickness / GetIdealSliceSpacing(volumeReference, slicerAxisZ) + 0.5)); // project the corners of the volume on to the slicer axes to determine the bounds of the volume in the slicer frame float minBoundsX = float.MaxValue, minBoundsY = float.MaxValue, minBoundsZ = float.MaxValue; float maxBoundsX = float.MinValue, maxBoundsY = float.MinValue, maxBoundsZ = float.MinValue; var volumeDimensions = volumeReference.VolumeSize; foreach (var corner in new[] { new Vector3D(0, 0, 0), new Vector3D(0, 0, volumeDimensions.Z), new Vector3D(0, volumeDimensions.Y, 0), new Vector3D(0, volumeDimensions.Y, volumeDimensions.Z), new Vector3D(volumeDimensions.X, 0, 0), new Vector3D(volumeDimensions.X, 0, volumeDimensions.Z), new Vector3D(volumeDimensions.X, volumeDimensions.Y, 0), new Vector3D(volumeDimensions.X, volumeDimensions.Y, volumeDimensions.Z) }.Select(volumeReference.ConvertToPatient)) { var projection = corner.Dot(slicerAxisX); if (minBoundsX > projection) { minBoundsX = projection; } if (maxBoundsX < projection) { maxBoundsX = projection; } projection = corner.Dot(slicerAxisY); if (minBoundsY > projection) { minBoundsY = projection; } if (maxBoundsY < projection) { maxBoundsY = projection; } projection = corner.Dot(slicerAxisZ); if (minBoundsZ > projection) { minBoundsZ = projection; } if (maxBoundsZ < projection) { maxBoundsZ = projection; } } // get the origin of the slicer frame in patient coordinates var slicerOrigin = minBoundsX * slicerAxisX + minBoundsY * slicerAxisY + minBoundsZ * slicerAxisZ; // get the dimensions (in patient units) of the region that bounds the volume projected to the slicer frame - i.e. the dimensions of the stack of output slices var stackWidth = SliceWidth.HasValue ? SliceWidth.Value : maxBoundsX - minBoundsX; var stackHeight = SliceHeight.HasValue ? SliceHeight.Value : maxBoundsY - minBoundsY; var stackDepth = maxBoundsZ - minBoundsZ; // get the rows and columns of the slice output var sliceColumns = Columns ?? (int)(Math.Abs(1.0 * stackWidth / pixelSpacing.Width) + 0.5); var sliceRows = Rows ?? (int)(Math.Abs(1.0 * stackHeight / pixelSpacing.Height) + 0.5); // capture all the slicer parameters in an args object var args = new VolumeSliceArgs(sliceRows, sliceColumns, pixelSpacing.Height, pixelSpacing.Width, slicerAxisX, slicerAxisY, sliceThickness, sliceSubsamples, Interpolation, Projection); // compute the image position patient for each output slice and create the slices return(GetSlicePositions(slicerOrigin, slicerAxisX, slicerAxisY, slicerAxisZ, stackDepth, sliceRows, sliceColumns, pixelSpacing, sliceSpacing, sliceThickness, startPosition, endPosition, count) .Select(p => new VolumeSlice(volumeReference.Clone(), true, args, p, sliceSpacing))); }
public VolumeSlice(IVolumeReference volumeReference, bool ownReference, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float?spacingBetweenSlices = null) : this(ownReference ? volumeReference : volumeReference.Clone(), sliceArgs, imagePositionPatient, spacingBetweenSlices) { }
public VolumeSlice(Volume volume, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float?spacingBetweenSlices = null) : this(volume.CreateReference(), sliceArgs, imagePositionPatient, spacingBetweenSlices) { }
protected virtual void Dispose(bool disposing) { if (!disposing) return; if (_volumeReference != null) { _volumeReference.Dispose(); _volumeReference = null; } _sliceArgs = null; _imagePositionPatient = null; }
/// <summary> /// Creates an implementation of <see cref="IVolumeSlicerCore"/> for slicing the requested volume. /// </summary> /// <param name="volumeReference">Reference to the <see cref="Volume"/> to be resliced.</param> /// <param name="args">The requested reslicing parameters.</param> public static IVolumeSlicerCore Create(IVolumeReference volumeReference, VolumeSliceArgs args) { if (_coreProviders == null) { try { _coreProviders = new VolumeSlicerCoreProviderExtensionPoint().CreateExtensions().Cast<IVolumeSlicerCoreProvider>().ToList(); } catch (Exception ex) { Platform.Log(LogLevel.Error, ex, "Failed to initialize implementations on VolumeSlicerCoreProviderExtensionPoint"); } } if (_coreProviders == null || !_coreProviders.Any()) { #if UNIT_TESTS // ensures that unit tests running under a custom extension factory will always have a slicer implementation where available _coreProviders = Platform.PluginManager.ExtensionPoints .First(e => e.ExtensionPointClass == typeof (VolumeSlicerCoreProviderExtensionPoint)) .ListExtensions().Select(x => Activator.CreateInstance(x.ExtensionClass.Resolve())) .Cast<IVolumeSlicerCoreProvider>().ToList(); if (_coreProviders == null || !_coreProviders.Any()) throw new NotSupportedException("No implementations of IVolumeSlicerCoreProvider were found."); #else throw new NotSupportedException("No implementations of IVolumeSlicerCoreProvider were found."); #endif } try { return _coreProviders.First(c => c.IsSupported(args)).CreateSlicerCore(volumeReference, args); } catch (Exception ex) { throw new NotSupportedException("No suitable implementation of IVolumeSlicerCoreProvider was found.", ex); } }
public VolumeSlice(IVolumeReference volumeReference, bool ownReference, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float? spacingBetweenSlices = null) : this(ownReference ? volumeReference : volumeReference.Clone(), sliceArgs, imagePositionPatient, spacingBetweenSlices) {}
public VolumeSlice(Volume volume, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float? spacingBetweenSlices = null) : this(volume.CreateReference(), sliceArgs, imagePositionPatient, spacingBetweenSlices) {}
public IVolumeSlicerCore CreateSlicerCore(IVolumeReference volumeReference, VolumeSliceArgs args) { return new VtkVolumeSlicerCore(volumeReference, args); }
private IEnumerable<VolumeSlice> CreateSlicesCore(IVolumeReference volumeReference, Vector3D startPosition, Vector3D endPosition, int count) { // get the axes of the output plane and its normal in patient coordinates - these are the axes of the slicer frame var slicerAxisX = (RowOrientationPatient ?? volumeReference.VolumeOrientationPatientX).Normalize(); var slicerAxisY = (ColumnOrientationPatient ?? volumeReference.VolumeOrientationPatientY).Normalize(); var slicerAxisZ = (StackOrientationPatient ?? slicerAxisX.Cross(slicerAxisY)).Normalize(); // get the pixel spacing (defaults to isotropic spacing based on smallest volume spacing dimension) var pixelSpacing = GetPixelSpacing(volumeReference); // get the spacing between slices (defaults to projecting voxel diagonal on to normal axis) var sliceSpacing = GetSliceSpacing(volumeReference, slicerAxisZ); // get the thickness of each slice (defaults to slice spacing) var sliceThickness = SliceThickness ?? sliceSpacing; // get the ideal subsampling for the slice thickness (if thickness exceeds threshold, create thin slices and aggregate them as a slab) var sliceSubsamples = Math.Max(1, (int) (sliceThickness/GetIdealSliceSpacing(volumeReference, slicerAxisZ) + 0.5)); if (sliceSubsamples > 1) sliceSubsamples *= 2; // if slabbing required, double the subsampling rate to achieve Nyquist sampling and ensure we don't miss any data // project the corners of the volume on to the slicer axes to determine the bounds of the volume in the slicer frame float minBoundsX = float.MaxValue, minBoundsY = float.MaxValue, minBoundsZ = float.MaxValue; float maxBoundsX = float.MinValue, maxBoundsY = float.MinValue, maxBoundsZ = float.MinValue; var volumeDimensions = volumeReference.VolumeSize; foreach (var corner in new[] { new Vector3D(0, 0, 0), new Vector3D(0, 0, volumeDimensions.Z), new Vector3D(0, volumeDimensions.Y, 0), new Vector3D(0, volumeDimensions.Y, volumeDimensions.Z), new Vector3D(volumeDimensions.X, 0, 0), new Vector3D(volumeDimensions.X, 0, volumeDimensions.Z), new Vector3D(volumeDimensions.X, volumeDimensions.Y, 0), new Vector3D(volumeDimensions.X, volumeDimensions.Y, volumeDimensions.Z) }.Select(volumeReference.ConvertToPatient)) { var projection = corner.Dot(slicerAxisX); if (minBoundsX > projection) minBoundsX = projection; if (maxBoundsX < projection) maxBoundsX = projection; projection = corner.Dot(slicerAxisY); if (minBoundsY > projection) minBoundsY = projection; if (maxBoundsY < projection) maxBoundsY = projection; projection = corner.Dot(slicerAxisZ); if (minBoundsZ > projection) minBoundsZ = projection; if (maxBoundsZ < projection) maxBoundsZ = projection; } // get the origin of the slicer frame in patient coordinates var slicerOrigin = minBoundsX*slicerAxisX + minBoundsY*slicerAxisY + minBoundsZ*slicerAxisZ; // get the dimensions (in patient units) of the region that bounds the volume projected to the slicer frame - i.e. the dimensions of the stack of output slices var stackWidth = SliceWidth.HasValue ? SliceWidth.Value : maxBoundsX - minBoundsX; var stackHeight = SliceHeight.HasValue ? SliceHeight.Value : maxBoundsY - minBoundsY; var stackDepth = maxBoundsZ - minBoundsZ; // get the rows and columns of the slice output var sliceColumns = Columns ?? (int) (Math.Abs(1.0*stackWidth/pixelSpacing.Width) + 0.5); var sliceRows = Rows ?? (int) (Math.Abs(1.0*stackHeight/pixelSpacing.Height) + 0.5); // capture all the slicer parameters in an args object var args = new VolumeSliceArgs(sliceRows, sliceColumns, pixelSpacing.Height, pixelSpacing.Width, slicerAxisX, slicerAxisY, sliceThickness, sliceSubsamples, Interpolation, Projection); // compute the image position patient for each output slice and create the slices var slicePositions = GetSlicePositions(slicerOrigin, slicerAxisX, slicerAxisY, slicerAxisZ, stackDepth, sliceRows, sliceColumns, pixelSpacing, sliceSpacing, sliceThickness, startPosition, endPosition, count).ToList(); return slicePositions.Select(p => new VolumeSlice(volumeReference.Clone(), true, args, p, slicePositions.Count > 1 ? (float?) sliceSpacing : null)); }
/// <summary> /// Initializes a new instance of <see cref="VtkVolumeSlicerCore"/>. /// </summary> /// <param name="volumeReference"></param> /// <param name="args"></param> public VtkVolumeSlicerCore(IVolumeReference volumeReference, VolumeSliceArgs args) : base(volumeReference, args) {}
private static VolumeSlice CreateSlice(IVolumeReference volumeReference, IVolumeSlicerParams slicerParams, float thicknessAndSpacing, Vector3D throughPoint) { // compute Rows and Columns to reflect actual output size var frameSize = GetSliceExtent(volumeReference, slicerParams); // compute Pixel Spacing var effectiveSpacing = GetEffectiveSpacing(volumeReference); // compute Image Orientation (Patient) var matrix = new Matrix(slicerParams.SlicingPlaneRotation); matrix[3, 0] = throughPoint.X; matrix[3, 1] = throughPoint.Y; matrix[3, 2] = throughPoint.Z; var resliceAxesPatientOrientation = volumeReference.RotateToPatientOrientation(matrix); // compute Image Position (Patient) var topLeftOfSlicePatient = GetTopLeftOfSlicePatient(frameSize, throughPoint, volumeReference, slicerParams); var args = new VolumeSliceArgs(frameSize.Height, frameSize.Width, effectiveSpacing, effectiveSpacing, new Vector3D(resliceAxesPatientOrientation[0, 0], resliceAxesPatientOrientation[0, 1], resliceAxesPatientOrientation[0, 2]), new Vector3D(resliceAxesPatientOrientation[1, 0], resliceAxesPatientOrientation[1, 1], resliceAxesPatientOrientation[1, 2]), thicknessAndSpacing, Convert(slicerParams.InterpolationMode)); return new VolumeSlice(volumeReference, true, args, topLeftOfSlicePatient, thicknessAndSpacing); }