private static bool IsSupportedGantryTilt(IList <Frame> frames) { try { using (IPresentationImage firstImage = ImageViewer.PresentationImageFactory.Create(frames[0])) { using (IPresentationImage lastImage = ImageViewer.PresentationImageFactory.Create(frames[frames.Count - 1])) { // neither of these should return null since we already checked for image orientation and position (patient) DicomImagePlane firstImagePlane = DicomImagePlane.FromImage(firstImage); DicomImagePlane lastImagePlane = DicomImagePlane.FromImage(lastImage); Vector3D stackZ = lastImagePlane.PositionPatientTopLeft - firstImagePlane.PositionPatientTopLeft; Vector3D imageX = firstImagePlane.PositionPatientTopRight - firstImagePlane.PositionPatientTopLeft; if (!stackZ.IsOrthogonalTo(imageX, _gantryTiltTolerance)) { // this is a gantry slew (gantry tilt about Y axis) return(false); } } } return(true); } catch (Exception ex) { Platform.Log(LogLevel.Debug, ex, "Unexpected exception encountered while checking for supported gantry tilts"); return(false); } }
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); } } }
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(); } } }
/// <summary> /// Sets this line segment's end points to be the intersection of the <paramref name="sliceImage"/> on the infinite plane of the <paramref name="referenceImage"/>. /// </summary> /// <remarks> /// In practice, a call to this method should have <paramref name="referenceImage"/> being equal to this line's <see cref="Graphic.ParentPresentationImage"/> or, /// if not, then followed by a call to <see cref="ResliceToolGroup.TranslocateGraphic">translocate</see> the line to the <paramref name="referenceImage"/>. /// Any other use may constitute a defect involving reference line bounds, and you should thusly inspect your code and explain why this is the case. /// </remarks> /// <param name="sliceImage">The slice whose position is controlled by this line.</param> /// <param name="referenceImage">The image on which the line is (or is to be) defined.</param> /// <returns>Returns true if a solution exists and the end points were updated.</returns> public bool SetLine(IPresentationImage sliceImage, IPresentationImage referenceImage) { DicomImagePlane sliceImagePlane = DicomImagePlane.FromImage(sliceImage); DicomImagePlane referenceImagePlane = DicomImagePlane.FromImage(referenceImage); if (!sliceImagePlane.IsParallelTo(referenceImagePlane, 1f)) { Vector3D imagePt1 = referenceImagePlane.ConvertToImagePlane(sliceImagePlane.PositionPatientTopLeft); Vector3D imagePt2 = referenceImagePlane.ConvertToImagePlane(sliceImagePlane.PositionPatientTopRight); this.Points.SuspendEvents(); this.Points.Clear(); this.Points.Add(referenceImagePlane.ConvertToImage(new PointF(imagePt1.X, imagePt1.Y))); this.Points.Add(referenceImagePlane.ConvertToImage(new PointF(imagePt2.X, imagePt2.Y))); this.Points.ResumeEvents(); return(true); } return(false); }
private void Probe(Point destinationPoint) { Point sourcePointRounded = Point.Truncate(_selectedImageGraphic.SpatialTransform.ConvertToSource(destinationPoint)); bool showPixelValue = true; bool showModalityValue = true; bool showVoiValue = true; string probeString = String.Format(SR.FormatLocation, SR.LabelNotApplicable, SR.LabelNotApplicable, SR.LabelNotApplicable); string pixelValueString = String.Format(SR.FormatPixelValue, SR.LabelNotApplicable); string modalityLutString = String.Format(SR.FormatModalityLutValue, SR.LabelNotApplicable); string voiLutString = String.Format(SR.FormatVoiLutValue, SR.LabelNotApplicable); try { DicomImagePlane dip = DicomImagePlane.FromImage(this.SelectedPresentationImage); if (_selectedImageGraphic.HitTest(destinationPoint)) { Vector3D voxelCoordinate = dip.ConvertToPatient(new PointF(sourcePointRounded.X, sourcePointRounded.Y)); probeString = String.Format(SR.FormatLocation, voxelCoordinate.X, voxelCoordinate.Y, voxelCoordinate.Z); if (_selectedImageGraphic is GrayscaleImageGraphic) { GrayscaleImageGraphic image = _selectedImageGraphic as GrayscaleImageGraphic; int pixelValue = 0; double modalityLutValue = 0; double voiLutValue = 0; GetPixelValue(image, sourcePointRounded, ref pixelValue, ref pixelValueString); GetModalityLutValue(image, pixelValue, ref modalityLutValue, ref modalityLutString); GetVoiLutValue(image, modalityLutValue, ref voiLutValue, ref voiLutString); } else if (_selectedImageGraphic is ColorImageGraphic) { showModalityValue = false; showVoiValue = false; ColorImageGraphic image = _selectedImageGraphic as ColorImageGraphic; Color color = image.PixelData.GetPixelAsColor(sourcePointRounded.X, sourcePointRounded.Y); string rgbFormatted = String.Format(SR.FormatRgb, color.R, color.G, color.B); pixelValueString = String.Format(SR.FormatPixelValue, rgbFormatted); } else { showPixelValue = false; showModalityValue = false; showVoiValue = false; } } if (showPixelValue) { probeString += "\n" + pixelValueString; } if (showModalityValue) { probeString += "\n" + modalityLutString; } if (showVoiValue) { probeString += "\n" + voiLutString; } } catch (Exception e) { Platform.Log(LogLevel.Error, e); probeString = SR.MessageProbeToolError; } _selectedTile.InformationBox.Update(probeString, destinationPoint); }