Beispiel #1
0
		/// <summary>
		/// Initializes a new instance of <see cref="Frame"/> with the
		/// specified parameters.
		/// </summary>
		/// <param name="parentImageSop">The parent <see cref="ImageSop"/>.</param>
		/// <param name="frameNumber">The first frame is frame 1.</param>
		protected internal Frame(ImageSop parentImageSop, int frameNumber)
		{
			Platform.CheckForNullReference(parentImageSop, "parentImageSop");
			Platform.CheckPositive(frameNumber, "frameNumber");
			_parentImageSop = parentImageSop;
			_frameNumber = frameNumber;
		}
Beispiel #2
0
 /// <summary>
 /// Initializes a new instance of <see cref="Frame"/> with the
 /// specified parameters.
 /// </summary>
 /// <param name="parentImageSop">The parent <see cref="ImageSop"/>.</param>
 /// <param name="frameNumber">The first frame is frame 1.</param>
 protected internal Frame(ImageSop parentImageSop, int frameNumber)
 {
     Platform.CheckForNullReference(parentImageSop, "parentImageSop");
     Platform.CheckPositive(frameNumber, "frameNumber");
     _parentImageSop = parentImageSop;
     _frameNumber    = frameNumber;
 }
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				_frame = null;
				_dicomFile = null;

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

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

				if (_filename != null)
				{
					if (File.Exists(_filename))
						File.Delete(_filename);
					_filename = null;
				}
			}
			base.Dispose(disposing);
		}
Beispiel #4
0
		private static void TestVolume(bool signed, VolumeFunction f, IEnumerable<IVolumeSlicerParams> slicerParams, string testName, ImageKernelFunction imageKernel, VolumeKernelFunction volumeKernel)
		{
			const int FULL_SCALE = 65535;
			VolumeFunction normalizedFunction = f.Normalize(100);

			using (Volume volume = normalizedFunction.CreateVolume(100, signed))
			{
				float offset = signed ? -32768 : 0;
				foreach (IVolumeSlicerParams slicing in slicerParams)
				{
					List<double> list = new List<double>();
					using (VolumeSlicer slicer = new VolumeSlicer(volume, slicing, DicomUid.GenerateUid().UID))
					{
						foreach (ISopDataSource slice in slicer.CreateSlices())
						{
							using (ImageSop imageSop = new ImageSop(slice))
							{
								foreach (IPresentationImage image in PresentationImageFactory.Create(imageSop))
								{
									IImageSopProvider imageSopProvider = (IImageSopProvider) image;
									IImageGraphicProvider imageGraphicProvider = (IImageGraphicProvider) image;
									DicomImagePlane dip = DicomImagePlane.FromImage(image);

									for (int y = 1; y < imageSopProvider.Frame.Rows - 1; y++)
									{
										for (int x = 1; x < imageSopProvider.Frame.Columns - 1; x++)
										{
											// pixels on the extreme sides of the volume tend to have more interpolation error due to MPR padding values
											Vector3D vector = dip.ConvertToPatient(new PointF(x, y)); // +new Vector3D(-0.5f, -0.5f, 0);
											if (Between(vector.X, 1, 98) && Between(vector.Y, 1, 98) && Between(vector.Z, 1, 98))
											{
												float expected = volumeKernel.Invoke(normalizedFunction, vector.X, vector.Y, vector.Z) + offset;
												float actual = imageKernel.Invoke(imageGraphicProvider.ImageGraphic.PixelData, x, y);
												list.Add(Math.Abs(expected - actual));
											}
										}
									}

									image.Dispose();
								}
							}
							slice.Dispose();
						}
					}

					Statistics stats = new Statistics(list);
					Trace.WriteLine(string.Format("Testing {0}", testName));
					Trace.WriteLine(string.Format("\tFunction/Slicing: {0} / {1}", normalizedFunction.Name, slicing.Description));
					Trace.WriteLine(string.Format("\t       Pixel Rep: {0}", signed ? "signed" : "unsigned"));
					Trace.WriteLine(string.Format("\t Voxels Compared: {0}", list.Count));
					Trace.WriteLine(string.Format("\t      Mean Delta: {0:f2} ({1:p2} of full scale)", stats.Mean, stats.Mean/FULL_SCALE));
					Trace.WriteLine(string.Format("\t    StdDev Delta: {0:f2} ({1:p2} of full scale)", stats.StandardDeviation, stats.StandardDeviation/FULL_SCALE));
					Assert.Less(stats.Mean, FULL_SCALE*0.05, "Mean delta exceeds 5% of full scale ({0})", FULL_SCALE);
					Assert.Less(stats.StandardDeviation, FULL_SCALE*0.05, "StdDev delta exceeds 5% of full scale ({0})", FULL_SCALE);
				}
			}
		}
		public TestPresentationImage() : base(TestPattern.CreateRGBKCorners(new Size(_width, _height)))
		{
			DicomFile dcf = new DicomFile();
			dcf.DataSet[DicomTags.StudyInstanceUid].SetStringValue("1");
			dcf.DataSet[DicomTags.SeriesInstanceUid].SetStringValue("2");
			dcf.DataSet[DicomTags.SopInstanceUid].SetStringValue("3");
			dcf.DataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid);
			dcf.DataSet[DicomTags.InstanceNumber].SetStringValue("1");
			dcf.DataSet[DicomTags.NumberOfFrames].SetStringValue("1");
			dcf.MetaInfo[DicomTags.TransferSyntaxUid].SetStringValue(TransferSyntax.ImplicitVrLittleEndianUid);
			dcf.MetaInfo[DicomTags.MediaStorageSopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid);
			dcf.MetaInfo[DicomTags.MediaStorageSopInstanceUid].SetStringValue("3");
			_imageSop = new ImageSop(new TestDataSource(dcf));
		}
Beispiel #6
0
		public override bool Start(IMouseInformation mouseInformation)
		{
			if (this.SelectedImageGraphicProvider == null)
				return false;

			_selectedTile = mouseInformation.Tile as Tile;
			_selectedTile.InformationBox = new InformationBox();
			_selectedImageGraphic = this.SelectedImageGraphicProvider.ImageGraphic;
			_selectedImageSop = (this.SelectedPresentationImage as IImageSopProvider).ImageSop;

			Probe(mouseInformation.Location);

			return true;
		}
		public MockDicomPresentationImage(string filename) : base(new GrayscaleImageGraphic(10, 10))
		{
			if (Path.IsPathRooted(filename))
				_filename = filename;
			else
				_filename = Path.Combine(Environment.CurrentDirectory, filename);

			_dicomFile = new DicomFile();
			_dicomFile.DataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid);
			_dicomFile.DataSet[DicomTags.SopInstanceUid].SetStringValue(DicomUid.GenerateUid().UID);
			_dicomFile.MetaInfo[DicomTags.MediaStorageSopClassUid].SetStringValue(_dicomFile.DataSet[DicomTags.SopClassUid].ToString());
			_dicomFile.MetaInfo[DicomTags.MediaStorageSopInstanceUid].SetStringValue(_dicomFile.DataSet[DicomTags.SopInstanceUid].ToString());
			_dicomFile.Save(_filename);
			_sopDataSource = new LocalSopDataSource(_dicomFile);
			_imageSop = new ImageSop(_sopDataSource);
			_frame = new MockFrame(_imageSop, 1);
		}
Beispiel #8
0
		private static DynamicTePresentationImage CreateT2Image(ImageSop imageSop, Frame frame)
		{
			DicomFile pdMap = FindMap(imageSop.StudyInstanceUID, frame.SliceLocation, "PD");
			pdMap.Load(DicomReadOptions.Default);

			DicomFile t2Map = FindMap(imageSop.StudyInstanceUID, frame.SliceLocation, "T2");
			t2Map.Load(DicomReadOptions.Default);

			DicomFile probMap = FindMap(imageSop.StudyInstanceUID, frame.SliceLocation, "CHI2PROB");
			probMap.Load(DicomReadOptions.Default);

			DynamicTePresentationImage t2Image = new DynamicTePresentationImage(
				frame,
				(byte[])pdMap.DataSet[DicomTags.PixelData].Values,
				(byte[])t2Map.DataSet[DicomTags.PixelData].Values,
				(byte[])probMap.DataSet[DicomTags.PixelData].Values);

			t2Image.DynamicTe.Te = 50.0f;
			return t2Image;
		}
Beispiel #9
0
        public List<BitmapSource> ReturnImageListFromFile(string filePath)
        {
            List<BitmapSource> bmpImageList = new List<BitmapSource>();

            LocalSopDataSource dicomDataSource = new LocalSopDataSource(filePath);
            ImageSop imageSop = new ImageSop(dicomDataSource);
            IEnumerable images = PresentationImageFactory.Create(imageSop).ToArray();

            int i = 1;
            foreach (IPresentationImage presentationImage in images)
            {
                int width = imageSop.Frames[i].Columns;

                int height = imageSop.Frames[i].Rows;

                Bitmap bmp = presentationImage.DrawToBitmap(width, height);

                dicomImages.Add(new DicomImage { Bitmap = Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(width, height)) });
                i++;
            }

            return bmpImageList;
        }
Beispiel #10
0
		protected internal byte[] GetOverlay(Frame baseFrame, out OverlayFrameParams overlayFrameParams)
		{
			var volume = this.Volume;

			// compute the bounds of the target base image frame in patient coordinates
			var baseTopLeft = baseFrame.ImagePlaneHelper.ConvertToPatient(new PointF(0, 0));
			var baseTopRight = baseFrame.ImagePlaneHelper.ConvertToPatient(new PointF(baseFrame.Columns, 0));
			var baseBottomLeft = baseFrame.ImagePlaneHelper.ConvertToPatient(new PointF(0, baseFrame.Rows));
			var baseFrameCentre = (baseTopRight + baseBottomLeft)/2;

			// compute the rotated volume slicing basis axes
			var volumeXAxis = (volume.ConvertToVolume(baseTopRight) - volume.ConvertToVolume(baseTopLeft)).Normalize();
			var volumeYAxis = (volume.ConvertToVolume(baseBottomLeft) - volume.ConvertToVolume(baseTopLeft)).Normalize();
			var volumeZAxis = volumeXAxis.Cross(volumeYAxis);

			var @params = new VolumeSlicerParams(volumeXAxis, volumeYAxis, volumeZAxis);
			using (var slice = new VolumeSliceSopDataSource(volume, @params, volume.ConvertToVolume(baseFrameCentre)))
			{
				using (var sliceSop = new ImageSop(slice))
				{
					using (var overlayFrame = sliceSop.Frames[1])
					{
						// compute the bounds of the target overlay image frame in patient coordinates
						var overlayTopLeft = overlayFrame.ImagePlaneHelper.ConvertToPatient(new PointF(0, 0));
						var overlayTopRight = overlayFrame.ImagePlaneHelper.ConvertToPatient(new PointF(overlayFrame.Columns, 0));
						var overlayBottomLeft = overlayFrame.ImagePlaneHelper.ConvertToPatient(new PointF(0, overlayFrame.Rows));
						var overlayOffset = overlayTopLeft - baseTopLeft;

						// compute the overlay and base image resolution in pixels per unit patient space (mm).
						var overlayResolutionX = overlayFrame.Columns/(overlayTopRight - overlayTopLeft).Magnitude;
						var overlayResolutionY = overlayFrame.Rows/(overlayBottomLeft - overlayTopLeft).Magnitude;
						var baseResolutionX = baseFrame.Columns/(baseTopRight - baseTopLeft).Magnitude;
						var baseResolutionY = baseFrame.Rows/(baseBottomLeft - baseTopLeft).Magnitude;

						// compute parameters to register the overlay on the base image
						var scale = new PointF(baseResolutionX/overlayResolutionX, baseResolutionY/overlayResolutionY);
						var offset = new PointF(overlayOffset.X*overlayResolutionX, overlayOffset.Y*overlayResolutionY);

						//TODO (CR Sept 2010): could this be negative?
						// validate computed transform parameters
						Platform.CheckTrue(overlayOffset.Z < 0.5f, "Compute OffsetZ != 0");

						overlayFrameParams = new OverlayFrameParams(
							overlayFrame.Rows, overlayFrame.Columns,
							overlayFrame.BitsAllocated, overlayFrame.BitsStored,
							overlayFrame.HighBit, overlayFrame.PixelRepresentation != 0 ? true : false,
							overlayFrame.PhotometricInterpretation == PhotometricInterpretation.Monochrome1 ? true : false,
							overlayFrame.RescaleSlope, overlayFrame.RescaleIntercept,
							scale, offset);

						return overlayFrame.GetNormalizedPixelData();
					}
				}
			}
		}
Beispiel #11
0
		protected internal AsyncFrame(ImageSop parentImageSop, int frameNumber)
			: base(parentImageSop, frameNumber)
		{
			SupportsAsync = ParentImageSop.DataSource.GetFrameData(FrameNumber) is IAsyncSopFrameData;
		}
Beispiel #12
0
		public StoredLayout GetLayout(ImageSop imageSop)
		{
			if (imageSop == null)
				return this.DefaultLayout;

			return GetLayout(imageSop.Modality);
		}
		private static void AssertExposureParameter(string expectedValue, ImageSop imageSop, ExposureParameterGetter function, string message)
		{
			Assert.AreEqual(expectedValue, function.Invoke(imageSop.Frames[1], @"{0}"), message);
		}
		/// <summary>
		/// Creates an appropriate subclass of <see cref="BasicPresentationImage"/>
		/// for each <see cref="Frame"/> in the input <see cref="ImageSop"/>.
		/// </summary>
		public static List<IPresentationImage> Create(ImageSop imageSop)
		{
			return _defaultInstance.CreateImages(imageSop);
		}
		/// <summary>
		/// Creates the presentation images for a given image SOP.
		/// </summary>
		/// <param name="imageSop">The image SOP from which presentation images are to be created.</param>
		/// <returns>A list of created presentation images.</returns>
		protected virtual List<IPresentationImage> CreateImages(ImageSop imageSop)
		{
			return CollectionUtils.Map(imageSop.Frames, (Frame frame) => CreateImage(frame));
		}
Beispiel #16
0
 public static bool IsValid(TreeNode node)
 {
     try
     {
         LocalSopDataSource _dicomDataSource = new LocalSopDataSource(((FileInfo)node.Tag).FullName);
         ImageSop isop = new ImageSop(_dicomDataSource);
         //DicomFile dcf = new DicomFile(((FileInfo)node.Tag).FullName);
         //dcf.Load(DicomReadOptions.DoNotStorePixelDataInDataSet);
         //00:00:01.5625000
         //00:00:01.7625000
         //00:00:00.0468750
     }
     catch (Exception ex)
     {
         return false;
     }
     return true;
 }
Beispiel #17
0
    public static bool ConvertDcmToPng(DbStudy study)
    {        
        try
        {
            string dcmPath = ADCM.GetStoreString();
            string studyPath = Path.Combine(dcmPath, study.study_uid);
            if (!Directory.Exists(studyPath))
                throw new Exception("Study path not found");
            var allSeriesPaths = Directory.GetDirectories(studyPath);
            if (allSeriesPaths.Length < 1)
                throw new Exception("No series subdirectories");

            foreach (var s in allSeriesPaths)
            {
                var dcmFiles = Directory.GetFiles(s, "*.dcm");
                if (dcmFiles.Length < 1)
                    throw new Exception("No DCM files inside series path: " + s);
                DicomFile tempdcm = new DicomFile(dcmFiles[0]);
                tempdcm.Load();
                var seriesName = tempdcm.DataSet[DicomTags.SeriesDescription].GetString(0, null);
                var seriesUID = s.Substring(s.LastIndexOf(Path.DirectorySeparatorChar) + 1);
                if (string.IsNullOrEmpty(seriesName))
                    seriesName = "Unamed_Series";

                APetaPoco.SetConnectionString("cn1");
                var bm = APetaPoco.PpRetrieveOne<DbSeries>("Series", "[case_id] = '" + study.case_id + "' AND [series_uid] = '" + seriesUID + "'");
                DbSeries dbseries = null;
                if (bm.Success) { dbseries = (DbSeries)bm.Data; }

                string outputPath = Path.Combine(dcmPath, "OUTPUT", study.case_id, study.study_uid, seriesUID);
                if (!Directory.Exists(outputPath))
                    Directory.CreateDirectory(outputPath);

                //int fileCount = 0;

                for (int k = 0; k < dcmFiles.Length; k++)
                {
                    DicomFile dcmFile = new DicomFile(dcmFiles[k]);
                    dcmFile.Load();
                    int fileCount = 0;
                    var windowWidth = dcmFile.DataSet[DicomTags.WindowWidth].ToString();
                    if (!string.IsNullOrEmpty(windowWidth))
                    {
                        var tempSplitString = windowWidth.Split('\\');
                        windowWidth = tempSplitString[0];
                    }
                    var windowCenter = dcmFile.DataSet[DicomTags.WindowCenter].ToString();
                    if (!string.IsNullOrEmpty(windowCenter))
                    {
                        var tempSplitString = windowCenter.Split('\\');
                        windowCenter = tempSplitString[0];
                    }
                    var ww = dcmFile.DataSet[DicomTags.WindowWidth].GetFloat32(0, 0);
                    var wc = dcmFile.DataSet[DicomTags.WindowCenter].GetFloat32(0, 0);

                    if (ww == 0 && !string.IsNullOrEmpty(windowWidth))
                    {
                        if (windowWidth.Contains("."))
                        {
                            var tempSplitString = windowWidth.Split('.');
                            ww = int.Parse(tempSplitString[0]);
                        }
                        else
                        {
                            ww = int.Parse(windowWidth);
                        }

                    }
                    if (wc == 0 && !string.IsNullOrEmpty(windowCenter))
                    {
                        if (windowCenter.Contains("."))
                        {
                            var tempSplitString = windowCenter.Split('.');
                            wc = int.Parse(tempSplitString[0]);
                        }
                        else
                        {
                            wc = int.Parse(windowCenter);
                        }

                    }

                    LocalSopDataSource localds = new LocalSopDataSource(dcmFile);
                    if (!localds.IsImage) { continue; }
                    ImageSop sop = new ImageSop(localds);
                    int frameCount = sop.Frames.Count;
                    var fileName = dcmFile.DataSet[DicomTags.InstanceNumber].GetInt16(0, 0);
                    if (frameCount > 1)
                    {
                        for (int j = 1; j <= frameCount; j++)
                        {
                            GC.Collect();
                            Frame f = sop.Frames[j];
                            var jpgPath = Path.Combine(outputPath, fileName + "." + j + ".png");
                            Bitmap bmp = null;
                            if (string.IsNullOrEmpty(windowWidth) || string.IsNullOrEmpty(windowCenter))
                            {
                                bmp = DrawDefaultFrame(f);
                            }
                            else
                            {
                                bmp = DrawLutFrame(f, ww, wc);
                            }
                            if (bmp != null)
                            {
                                if(dbseries != null && dbseries.crop_h != null
                                    && dbseries.crop_w != null
                                    && dbseries.crop_x != null
                                    && dbseries.crop_y != null)
                                {
                                    bmp = Crop(bmp, dbseries.crop_x.Value, dbseries.crop_y.Value, dbseries.crop_w.Value, dbseries.crop_h.Value);
                                }
                                SaveImage(bmp, jpgPath);
                            }
                            fileCount += 1;
                            GC.Collect();
                        }
                    }
                    else
                    {
                        GC.Collect();
                        var jpgPath = Path.Combine(outputPath, fileName + ".png");
                        Frame f = sop.Frames[1];
                        Bitmap bmp = null;
                        if (string.IsNullOrEmpty(windowWidth) || string.IsNullOrEmpty(windowCenter))
                        {
                            bmp = DrawDefaultFrame(f);
                        }
                        else
                        {
                            bmp = DrawLutFrame(f, ww, wc);
                        }
                        if (bmp != null)
                        {
                            if (dbseries != null && dbseries.crop_h != null
                                    && dbseries.crop_w != null
                                    && dbseries.crop_x != null
                                    && dbseries.crop_y != null)
                            {
                                bmp = Crop(bmp, dbseries.crop_x.Value, dbseries.crop_y.Value, dbseries.crop_w.Value, dbseries.crop_h.Value);
                            }
                            SaveImage(bmp, jpgPath);
                        }
                        fileCount += 1;
                        GC.Collect();
                    }
                }
            }
            LOG.InsertEvent("Successfully converted study from DCM to PNG", "IMG", null, study.case_id, study.study_uid);
            return true;
        }
        catch (Exception ex)
        {
            string errorString = "Error at :" + System.Reflection.MethodBase.GetCurrentMethod().Name;
            LOG.Write(errorString);
            LOG.Write(ex.Message);
            LOG.InsertEvent(errorString, "IMG", ex.Message, study.case_id, study.study_uid);
            return false;
        }
        
    }       
Beispiel #18
0
    public static byte[] GetImageBytesFromDcm(string dcmPath)
    {
        DicomFile dcmFile = new DicomFile(dcmPath);
        dcmFile.Load();
        int fileCount = 0;
        var windowWidth = dcmFile.DataSet[DicomTags.WindowWidth].ToString();
        if (!string.IsNullOrEmpty(windowWidth))
        {
            var tempSplitString = windowWidth.Split('\\');
            windowWidth = tempSplitString[0];
        }
        var windowCenter = dcmFile.DataSet[DicomTags.WindowCenter].ToString();
        if (!string.IsNullOrEmpty(windowCenter))
        {
            var tempSplitString = windowCenter.Split('\\');
            windowCenter = tempSplitString[0];
        }
        var ww = dcmFile.DataSet[DicomTags.WindowWidth].GetFloat32(0, 0);
        var wc = dcmFile.DataSet[DicomTags.WindowCenter].GetFloat32(0, 0);

        if (ww == 0 && !string.IsNullOrEmpty(windowWidth))
        {
            if (windowWidth.Contains("."))
            {
                var tempSplitString = windowWidth.Split('.');
                ww = int.Parse(tempSplitString[0]);
            }
            else
            {
                ww = int.Parse(windowWidth);
            }

        }
        if (wc == 0 && !string.IsNullOrEmpty(windowCenter))
        {
            if (windowCenter.Contains("."))
            {
                var tempSplitString = windowCenter.Split('.');
                wc = int.Parse(tempSplitString[0]);
            }
            else
            {
                wc = int.Parse(windowCenter);
            }

        }

        LocalSopDataSource localds = new LocalSopDataSource(dcmFile);
        if (!localds.IsImage) { return null; }
        ImageSop sop = new ImageSop(localds);
        int frameCount = sop.Frames.Count;
        if (frameCount > 1)
        {
            int midFrame = Convert.ToInt32(frameCount / 2);
            GC.Collect();
            Frame f = sop.Frames[midFrame];
            //var jpgPath = Path.Combine(outputPath, fileName + "." + j + ".png");
            Bitmap bmp = null;
            if (string.IsNullOrEmpty(windowWidth) || string.IsNullOrEmpty(windowCenter))
            {
                bmp = DrawDefaultFrame(f);
            }
            else
            {
                bmp = DrawLutFrame(f, ww, wc);
            }
            if (bmp != null) { return ImageToByte2(bmp); }
        }
        else
        {
            GC.Collect();
            Frame f = sop.Frames[1];
            Bitmap bmp = null;
            if (string.IsNullOrEmpty(windowWidth) || string.IsNullOrEmpty(windowCenter))
            {
                bmp = DrawDefaultFrame(f);
            }
            else
            {
                bmp = DrawLutFrame(f, ww, wc);
            }
            if (bmp != null) { return ImageToByte2(bmp); }
            fileCount += 1;
            GC.Collect();
        }
        return null;
    }
		/// <summary>
		/// Creates a <see cref="ImageSopInstanceReferenceMacro"/> to the given <see cref="ImageSop"/>.
		/// </summary>
		/// <param name="sop">The image SOP to which a reference is to be constructed.</param>
		/// <returns>An image SOP instance reference macro item.</returns>
		protected static ImageSopInstanceReferenceMacro CreateImageSopInstanceReference(ImageSop sop)
		{
			ImageSopInstanceReferenceMacro imageReference = new ImageSopInstanceReferenceMacro();
			imageReference.ReferencedSopClassUid = sop.SopClassUid;
			imageReference.ReferencedSopInstanceUid = sop.SopInstanceUid;
			return imageReference;
		}
			public MockFrame(ImageSop parent, int number) : base(parent, number) {}
		public SingleImageDisplaySetDescriptor(ISeriesIdentifier sourceSeries, ImageSop imageSop, int position)
			: base(sourceSeries)
		{
            Platform.CheckForNullReference(sourceSeries, "sourceSeries");
            Platform.CheckForNullReference(imageSop, "imageSop");
            
            _sopInstanceUid = imageSop.SopInstanceUid;
			_seriesInstanceUid = imageSop.SeriesInstanceUid;
			_position = position;

			string laterality = imageSop.ImageLaterality;
			string viewPosition = imageSop.ViewPosition;
			if (string.IsNullOrEmpty(viewPosition))
			{
				DicomAttributeSQ codeSequence = imageSop[DicomTags.ViewCodeSequence] as DicomAttributeSQ;
                if (codeSequence != null && !codeSequence.IsNull && codeSequence.Count > 0)
					viewPosition = codeSequence[0][DicomTags.CodeMeaning].GetString(0, null);
			}

			string lateralityViewPosition = null;
			if (!String.IsNullOrEmpty(laterality) && !String.IsNullOrEmpty(viewPosition))
				lateralityViewPosition = String.Format("{0}/{1}", laterality, viewPosition);
			else if (!String.IsNullOrEmpty(laterality))
				lateralityViewPosition = laterality;
			else if (!String.IsNullOrEmpty(viewPosition))
				lateralityViewPosition = viewPosition;

			if (sourceSeries.SeriesInstanceUid == imageSop.SeriesInstanceUid)
			{
				if (lateralityViewPosition != null)
					_suffix = String.Format(SR.SuffixFormatSingleImageDisplaySetWithLateralityViewPosition, lateralityViewPosition, imageSop.InstanceNumber);
				else
					_suffix = String.Format(SR.SuffixFormatSingleImageDisplaySet, imageSop.InstanceNumber);
			}
			else
			{
				//this is a referenced image (e.g. key image).
				if (lateralityViewPosition != null)
					_suffix = String.Format(SR.SuffixFormatSingleReferencedImageDisplaySetWithLateralityViewPosition, 
						lateralityViewPosition, imageSop.SeriesNumber, imageSop.InstanceNumber);
				else
					_suffix = String.Format(SR.SuffixFormatSingleReferencedImageDisplaySet,
						imageSop.SeriesNumber, imageSop.InstanceNumber);
			}
		}
		public KeyImageReference(ImageSop imageSop, int? frameNumber)
			: base(imageSop)
		{
			_frameNumber = frameNumber;
		}
        private static void InitializeDerivationImageFunctionalGroup(FunctionalGroupsSequenceItem functionalGroupsSequenceItem, ImageSop imageSop, int frameNumber)
        {
            var derivationImageFunctionalGroup = functionalGroupsSequenceItem.GetFunctionalGroup<DerivationImageFunctionalGroup>();
            var derivationImageSequenceItem = derivationImageFunctionalGroup.CreateDerivationImageSequenceItem();
            var derivationCodeSequence = derivationImageSequenceItem.CreateDerivationCodeSequence();
            derivationCodeSequence.CodeValue = "113076";
            derivationCodeSequence.CodeMeaning = "Segmentation";
            derivationCodeSequence.CodingSchemeDesignator = "DCM";
            derivationImageSequenceItem.DerivationCodeSequence = derivationCodeSequence;
            var sourceImageSequenceItem = derivationImageSequenceItem.CreateSourceImageSequenceItem();
            sourceImageSequenceItem.ReferencedSopClassUid = imageSop.SopClassUid;
            sourceImageSequenceItem.ReferencedSopInstanceUid = imageSop.SopInstanceUid;
            if (frameNumber != 1)
                sourceImageSequenceItem.ReferencedFrameNumber2 = new[] {frameNumber};
            // TODO: FIXME: replace with stock implementation when available
            var purposeOfReferenceCodeSequence = new Func<CodeSequenceMacro>(() =>
                {
                    var dicomAttribute = sourceImageSequenceItem.DicomAttributeProvider[DicomTags.PurposeOfReferenceCodeSequence];
                    if (dicomAttribute.IsNull || dicomAttribute.IsEmpty)
                    {
                        var dicomSequenceItem = new DicomSequenceItem();
                        dicomAttribute.Values = new[] {dicomSequenceItem};
                        return new CodeSequenceMacro(dicomSequenceItem);
                    }
                    return new CodeSequenceMacro(((DicomSequenceItem[]) dicomAttribute.Values)[0]);
                }).Invoke();
            purposeOfReferenceCodeSequence.CodeValue = "121322";
            purposeOfReferenceCodeSequence.CodeMeaning = "Source image for image processing operation";
            purposeOfReferenceCodeSequence.CodingSchemeDesignator = "DCM";
            derivationImageSequenceItem.SourceImageSequence = new[] {sourceImageSequenceItem};

            derivationImageFunctionalGroup.DerivationImageSequence = new[] {derivationImageSequenceItem};
        }
		private static DisposableList<IPresentationImage> CreateImages(DicomFile dicomFile)
		{
			using (var dataSource = new LocalSopDataSource(dicomFile))
			{
				using (var sop = new ImageSop(dataSource))
				{
					return new DisposableList<IPresentationImage>(PresentationImageFactory.Create(sop));
				}
			}
		}
		protected static void ValidateVolumeSlicePoints(Volumes.Volume volume, IVolumeSlicerParams slicerParams, IList<KnownSample> expectedPoints,
		                                                double xAxialGantryTilt, double yAxialGantryTilt, bool gantryTiltInDegrees)
		{
			if (gantryTiltInDegrees)
			{
				xAxialGantryTilt *= Math.PI/180;
				yAxialGantryTilt *= Math.PI/180;
			}

			Trace.WriteLine(string.Format("Using slice plane: {0}", slicerParams.Description));
			using (VolumeSlicer slicer = new VolumeSlicer(volume, slicerParams))
			{
				foreach (ISopDataSource slice in slicer.CreateSliceSops())
				{
					using (ImageSop imageSop = new ImageSop(slice))
					{
						foreach (IPresentationImage image in PresentationImageFactory.Create(imageSop))
						{
							IImageGraphicProvider imageGraphicProvider = (IImageGraphicProvider) image;
							DicomImagePlane dip = DicomImagePlane.FromImage(image);

							foreach (KnownSample sample in expectedPoints)
							{
								Vector3D patientPoint = sample.Point;
								if (xAxialGantryTilt != 0 && yAxialGantryTilt == 0)
								{
									float cos = (float) Math.Cos(xAxialGantryTilt);
									float sin = (float) Math.Sin(xAxialGantryTilt);
									patientPoint = new Vector3D(patientPoint.X,
									                            patientPoint.Y*cos + (xAxialGantryTilt > 0 ? 100*sin : 0),
									                            patientPoint.Z/cos - patientPoint.Y*sin - (xAxialGantryTilt > 0 ? 100*sin*sin/cos : 0));
								}
								else if (yAxialGantryTilt != 0)
								{
									Assert.Fail("Unit test not designed to work with gantry tilts about Y (i.e. slew)");
								}

								Vector3D slicedPoint = dip.ConvertToImagePlane(patientPoint);
								if (slicedPoint.Z > -0.5 && slicedPoint.Z < 0.5)
								{
									int actual = imageGraphicProvider.ImageGraphic.PixelData.GetPixel((int) slicedPoint.X, (int) slicedPoint.Y);
									Trace.WriteLine(string.Format("Sample {0} @{1} (SLICE: {2}; PATIENT: {3})", actual, FormatVector(sample.Point), FormatVector(slicedPoint), FormatVector(patientPoint)));
									Assert.AreEqual(sample.Value, actual, "Wrong colour sample @{0}", sample.Point);
								}
							}

							image.Dispose();
						}
					}
					slice.Dispose();
				}
			}
		}
		public IPresentationImage CreateSecondaryCapture(IPresentationImage image)
		{
			var imageSopProvider = image as IImageSopProvider;
			if (imageSopProvider == null)
			{
				const string msg = "image must implement IImageSopProvider";
				throw new ArgumentException(msg, "image");
			}

			SeriesInfo seriesInfo;
			var seriesKey = MakeSeriesKey(imageSopProvider.Frame.StudyInstanceUid, imageSopProvider.Sop.Modality);
			if (!_seriesInfo.TryGetValue(seriesKey, out seriesInfo))
				_seriesInfo[seriesKey] = seriesInfo = new SeriesInfo(_nextSeriesNumberDelegate.Invoke(imageSopProvider.Frame.StudyInstanceUid));

			var dcf = CreatePrototypeFile(imageSopProvider.Sop.DataSource);
			FillGeneralSeriesModule(dcf.DataSet, imageSopProvider.Frame, seriesInfo);
			FillScEquipmentModule(dcf.DataSet, Manufacturer, ManufacturersModelName, SoftwareVersions);
			FillFrameOfReferenceModule(dcf.DataSet, imageSopProvider.Frame);
			FillGeneralImageModule(dcf.DataSet, imageSopProvider.Frame, seriesInfo);
			FillScImageModule(dcf.DataSet, imageSopProvider.Frame);
			FillImagePlaneModule(dcf.DataSet, imageSopProvider.Frame);
			FillSopCommonModule(dcf.DataSet, SopClass.SecondaryCaptureImageStorageUid);
			FillAuxiliaryImageData(dcf.DataSet, imageSopProvider.Frame);

			if (image is GrayscalePresentationImage)
			{
				FillModalityLutModule(dcf.DataSet, imageSopProvider.Frame);
				FillVoiLutModule(dcf.DataSet, imageSopProvider.Frame);

				// create image pixel last - this method may need to override some attributes set previously
				CreateImagePixelModuleGrayscale(dcf.DataSet, imageSopProvider.Frame);
			}
			else if (image is ColorPresentationImage)
			{
				// create image pixel last - this method may need to override some attributes set previously
				CreateImagePixelModuleColor(dcf.DataSet, imageSopProvider.Frame);
			}
			else
			{
				// create image pixel last - this method may need to override some attributes set previously
				CreateImagePixelModuleRasterRgb(dcf.DataSet, image);
			}

			dcf.MediaStorageSopClassUid = dcf.DataSet[DicomTags.SopClassUid].ToString();
			dcf.MediaStorageSopInstanceUid = dcf.DataSet[DicomTags.SopInstanceUid].ToString();
			_files.Add(dcf);

			using (var sop = new ImageSop(new LocalSopDataSource(dcf)))
			{
				var secondaryCapture = PresentationImageFactory.Create(sop).Single();
				try
				{
					var presentationState = DicomSoftcopyPresentationState.IsSupported(image) ? DicomSoftcopyPresentationState.Create(image) : null;
					if (presentationState != null)
					{
						presentationState.DeserializeOptions |= DicomSoftcopyPresentationStateDeserializeOptions.IgnoreImageRelationship;
						presentationState.Deserialize(secondaryCapture);

						// override the spatial transform of the secondary capture because the presentation state doesn't save exact parameters
						var sourceTransform = image as ISpatialTransformProvider;
						var targetTransform = secondaryCapture as ISpatialTransformProvider;
						if (sourceTransform != null && targetTransform != null)
						{
							targetTransform.SpatialTransform.CenterOfRotationXY = sourceTransform.SpatialTransform.CenterOfRotationXY;
							targetTransform.SpatialTransform.FlipX = sourceTransform.SpatialTransform.FlipX;
							targetTransform.SpatialTransform.FlipY = sourceTransform.SpatialTransform.FlipY;
							targetTransform.SpatialTransform.RotationXY = sourceTransform.SpatialTransform.RotationXY;
							targetTransform.SpatialTransform.Scale = sourceTransform.SpatialTransform.Scale;
							targetTransform.SpatialTransform.TranslationX = sourceTransform.SpatialTransform.TranslationX;
							targetTransform.SpatialTransform.TranslationY = sourceTransform.SpatialTransform.TranslationY;

							var sourceImageTransform = sourceTransform as IImageSpatialTransform;
							var targetImageTransform = targetTransform as IImageSpatialTransform;
							if (sourceImageTransform != null && targetImageTransform != null)
								targetImageTransform.ScaleToFit = sourceImageTransform.ScaleToFit;
						}
					}

					// force a render to update the client rectangle and scaling of the image
					secondaryCapture.RenderImage(image.ClientRectangle).Dispose();
				}
				catch (Exception ex)
				{
					Platform.Log(LogLevel.Warn, ex, "An error has occurred while deserializing the image presentation state.");
				}
				return secondaryCapture;
			}
		}