예제 #1
0
		/// <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;
		}
예제 #2
0
        /// <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;
        }
예제 #3
0
        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();
        }
예제 #4
0
        protected virtual void Dispose(bool disposing)
        {
            if (!disposing)
            {
                return;
            }

            if (_volumeReference != null)
            {
                _volumeReference.Dispose();
                _volumeReference = null;
            }

            _sliceArgs            = null;
            _imagePositionPatient = null;
        }
예제 #5
0
        /// <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);
            }
        }
예제 #6
0
		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();
		}
예제 #7
0
		public bool IsSupported(VolumeSliceArgs args)
		{
			return true;
		}
예제 #8
0
        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)));
        }
예제 #9
0
 public VolumeSlice(IVolumeReference volumeReference, bool ownReference, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float?spacingBetweenSlices = null)
     : this(ownReference ? volumeReference : volumeReference.Clone(), sliceArgs, imagePositionPatient, spacingBetweenSlices)
 {
 }
예제 #10
0
 public VolumeSlice(Volume volume, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float?spacingBetweenSlices = null)
     : this(volume.CreateReference(), sliceArgs, imagePositionPatient, spacingBetweenSlices)
 {
 }
예제 #11
0
		protected virtual void Dispose(bool disposing)
		{
			if (!disposing) return;

			if (_volumeReference != null)
			{
				_volumeReference.Dispose();
				_volumeReference = null;
			}

			_sliceArgs = null;
			_imagePositionPatient = null;
		}
예제 #12
0
		/// <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);
			}
		}
예제 #13
0
		public VolumeSlice(IVolumeReference volumeReference, bool ownReference, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float? spacingBetweenSlices = null)
			: this(ownReference ? volumeReference : volumeReference.Clone(), sliceArgs, imagePositionPatient, spacingBetweenSlices) {}
예제 #14
0
		public VolumeSlice(Volume volume, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float? spacingBetweenSlices = null)
			: this(volume.CreateReference(), sliceArgs, imagePositionPatient, spacingBetweenSlices) {}
예제 #15
0
		public IVolumeSlicerCore CreateSlicerCore(IVolumeReference volumeReference, VolumeSliceArgs args)
		{
			return new VtkVolumeSlicerCore(volumeReference, args);
		}
예제 #16
0
		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));
		}
예제 #17
0
		/// <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) {}
예제 #18
0
		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);
		}