private static int[] GreyScale(FramePixelData pixelData, int newWidth, int newHeight) { var resized = new int[newWidth * newHeight]; var stepX = pixelData.Width / (float)newWidth; var stepY = pixelData.Height / (float)newHeight; for (var y = 0; y < newHeight; y++) { for (var x = 0; x < newWidth; x++) { // We use a simple nearest neighbor sample as any blending // would only serve to increase the differences between the images. var sx = (int)(x * stepX); var sy = (int)(y * stepY); var si = sx + (sy * pixelData.Width); var scolor = pixelData.Data[si]; // Convert to a greyscale value which removes small // color differences that the eye cannot spot. var grayScale = (int)((scolor.R * 0.3) + (scolor.G * 0.59) + (scolor.B * 0.11)); var di = x + (y * newWidth); resized[di] = grayScale; } } return resized; }
private static int[] GreyScale(FramePixelData pixelData, int newWidth, int newHeight) { var resized = new int[newWidth * newHeight]; var stepX = pixelData.Width / (float)newWidth; var stepY = pixelData.Height / (float)newHeight; for (var y = 0; y < newHeight; y++) { for (var x = 0; x < newWidth; x++) { // We use a simple nearest neighbor sample as any blending // would only serve to increase the differences between the images. var sx = (int)(x * stepX); var sy = (int)(y * stepY); var si = sx + (sy * pixelData.Width); var scolor = pixelData.Data[si]; // Convert to a greyscale value which removes small // color differences that the eye cannot spot. var grayScale = (int)((scolor.R * 0.3) + (scolor.G * 0.59) + (scolor.B * 0.11)); var di = x + (y * newWidth); resized[di] = grayScale; } } return(resized); }
public float Compare (FramePixelData a, FramePixelData b) { int minWidth, maxWidth, minHeight, maxHeight; MathUtility.MinMax (a.Width, b.Width, out minWidth, out maxWidth); MathUtility.MinMax (a.Height, b.Height, out minHeight, out maxHeight); var rect = new System.Drawing.Rectangle (0, 0, minWidth, minHeight); long error = 0; int index = 0; for (int y = 0; y < rect.Height; ++y) { for (int x = 0; x < rect.Width; ++x) { error += Delta (a.Data [index], b.Data [index]); index++; } } // FIXME: To temporarily accommodate the differing // resolutions of mobile platforms, we just // ignore all non-overlapping pixels. This // is not ideal, but it's good enough for now. // Mark all out-of-bounds pixels as non-match. //error += PixelArgb.MaxDelta * ((maxWidth * maxHeight) - (minWidth * minHeight)); var dissimilarity = ((float) error / (float) (PixelArgb.MaxDelta * minWidth * minHeight)); // Project dissimilarity to a logarithmic scale. The // difference between having zero pixels wrong and one // pixel wrong is more significant than the difference // betweeen 10,000 wrong and 10,001. return 1.0f - (float) Math.Pow (dissimilarity, 0.5); }
private void WriteDiff(FramePixelData capture, FramePixelData reference, string outputPath) { var diff = CreateDiff(capture, reference); Normalize(diff); diff.Save(outputPath); }
protected static void WriteFrameDiffs( IEnumerable <FrameComparisonResult> results, string directory) { try { Directory.CreateDirectory(directory); } catch (IOException) { } foreach (var result in results) { string diffFileName = string.Format( "diff-{0}-{1}.png", Path.GetFileNameWithoutExtension(result.ReferenceImagePath), Path.GetFileNameWithoutExtension(result.CapturedImagePath)); string diffOutputPath = Path.Combine(directory, diffFileName); var a = FramePixelData.FromFile(result.ReferenceImagePath); var b = FramePixelData.FromFile(result.CapturedImagePath); var diff = CreateDiff(a, b); Normalize(diff); diff.Save(diffOutputPath); } }
public FramePixelDataRetriever(FramePixelData source) { _loader = source.Parent._loader; SopInstanceUid = source.Parent.SopInstanceUid; TransferSyntaxUid = source.Parent.TransferSyntaxUid; _frameNumber = source.FrameNumber; }
public float Compare(FramePixelData image, FramePixelData referenceImage) { // Conver the images down to a common sized greyscale image. var width = Math.Min(image.Width, referenceImage.Width); var height = Math.Min(image.Height, referenceImage.Height); var img = GreyScale(image, width, height); var imgRef = GreyScale(referenceImage, width, height); // Find the differences between the greyscale images. var absDiff = new int[width * height]; for (var i = 0; i < absDiff.Length; i++) { absDiff[i] = Math.Abs(img[i] - imgRef[i]); } // Find all the differences over the threshold. const int threshold = 3; var diffPixels = 0; for (var i = 0; i < absDiff.Length; i++) { if (absDiff[i] > threshold) { diffPixels++; } } // Calculate the difference percentage. var diff = diffPixels / (float)absDiff.Length; return(1.0f - diff); }
public float Compare(FramePixelData image, FramePixelData referenceImage) { // Conver the images down to a common sized greyscale image. var width = Math.Min(image.Width, referenceImage.Width); var height = Math.Min(image.Height, referenceImage.Height); var img = GreyScale(image, width, height); var imgRef = GreyScale(referenceImage, width, height); // Find the differences between the greyscale images. var absDiff = new int[width * height]; for (var i = 0; i < absDiff.Length; i++) absDiff[i] = Math.Abs(img[i] - imgRef[i]); // Find all the differences over the threshold. const int threshold = 3; var diffPixels = 0; for (var i = 0; i < absDiff.Length; i++) { if (absDiff[i] > threshold) diffPixels++; } // Calculate the difference percentage. var diff = diffPixels / (float)absDiff.Length; return 1.0f - diff; }
private static FramePixelData LoadOrCreateEmptyFramePixelData(string path) { try { return(FramePixelData.FromFile(path)); } catch (FileNotFoundException) { // TODO: It would be nice to communicate // information about what went wrong, when // things go wrong. return(new FramePixelData(0, 0, new Color[0])); } }
private void CompareAndWriteWorker() { // HACK: This should not be needed! Paths.SetStandardWorkingDirectory(); lock (_resultsSync) { while (true) { var workItem = _workItems.Take(); if (workItem == null) { break; } if (workItem.FrameOutputPath != null) { var directory = Path.GetDirectoryName(workItem.FrameOutputPath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } } float similarity; var framePixelData = new FramePixelData( workItem.TextureWidth, workItem.TextureHeight, workItem.TextureData); var comparePixelData = LoadOrCreateEmptyFramePixelData(workItem.ReferenceImagePath); similarity = CompareFrames( framePixelData, comparePixelData, workItem.FrameComparers); if (workItem.FrameOutputPath != null) { try { framePixelData.Save(workItem.FrameOutputPath); } catch (IOException) { // FIXME: Report this error somehow. } } _results.Add(new FrameComparisonResult( workItem.FrameInfo.DrawNumber, similarity, workItem.ReferenceImagePath, workItem.FrameOutputPath)); } } lock (_workThreadSync) { _workThread = null; } }
public FramePixelDataRetriever(FramePixelData source, MINTBinaryStream binaryStream, bool useBulkLoading) { BaseUrl = source.Parent.BinaryUri; StudyInstanceUid = source.Parent.StudyInstanceUid; SeriesInstanceUid = source.Parent.SeriesInstanceUid; SopInstanceUid = source.Parent.SopInstanceUid; FrameNumber = source.FrameNumber; TransferSyntaxUid = source.Parent.TransferSyntaxUid; BinaryStream = binaryStream; UseBulkLoading = useBulkLoading; }
public FrameComparisonResult(float similarity, FramePixelData captured, FramePixelData reference, string capturedImagePath, string referenceImagePath, bool failed, bool saveImage, bool saveDiff) { Similarity = similarity; CapturedData = captured; ReferenceData = reference; CapturedImagePath = capturedImagePath; ReferenceImagePath = referenceImagePath; Failed = failed; SaveImage = saveImage; SaveDiff = saveDiff; }
private static void Normalize(FramePixelData frame) { var max = new Color(0, 0, 0, 0); foreach (var pixel in frame.Data) { max.B = Math.Max(pixel.B, max.B); max.G = Math.Max(pixel.G, max.G); max.R = Math.Max(pixel.R, max.R); max.A = Math.Max(pixel.A, max.A); } if (max.B == 0) { max.B = 255; } if (max.G == 0) { max.G = 255; } if (max.R == 0) { max.R = 255; } if (max.A == 0) { max.A = 255; } for (var i = 0; i < frame.Data.Length; ++i) { var pixel = frame.Data[i]; pixel.B = (byte)(pixel.B * 255 / max.B); pixel.G = (byte)(pixel.G * 255 / max.G); pixel.R = (byte)(pixel.R * 255 / max.R); pixel.A = (byte)(pixel.A * 255 / max.A); frame.Data[i] = pixel; } }
private static float CompareFrames( FramePixelData image, FramePixelData referenceImage, Tuple <IFrameComparer, float> [] frameComparers) { float sumOfWeights = 0; foreach (var item in frameComparers) { sumOfWeights += item.Item2; } float similarity = 0; foreach (var item in frameComparers) { var comparer = item.Item1; var weight = item.Item2; similarity += comparer.Compare(image, referenceImage) * weight / sumOfWeights; } return(similarity); }
public float Compare(FramePixelData a, FramePixelData b) { int minWidth, maxWidth, minHeight, maxHeight; MathUtility.MinMax(a.Width, b.Width, out minWidth, out maxWidth); MathUtility.MinMax(a.Height, b.Height, out minHeight, out maxHeight); var rect = new System.Drawing.Rectangle(0, 0, minWidth, minHeight); long error = 0; int index = 0; for (int y = 0; y < rect.Height; ++y) { for (int x = 0; x < rect.Width; ++x) { error += Delta(a.Data [index], b.Data [index]); index++; } } // FIXME: To temporarily accommodate the differing // resolutions of mobile platforms, we just // ignore all non-overlapping pixels. This // is not ideal, but it's good enough for now. // Mark all out-of-bounds pixels as non-match. //error += PixelArgb.MaxDelta * ((maxWidth * maxHeight) - (minWidth * minHeight)); var dissimilarity = ((float)error / (float)(PixelArgb.MaxDelta * minWidth * minHeight)); // Project dissimilarity to a logarithmic scale. The // difference between having zero pixels wrong and one // pixel wrong is more significant than the difference // betweeen 10,000 wrong and 10,001. return(1.0f - (float)Math.Pow(dissimilarity, 0.5)); }
public FramePixelDataRetriever(FramePixelData source) { string host = source.Parent._host; string wadoPrefix = source.Parent._wadoUriPrefix; int wadoPort = source.Parent._wadoServicePort; try { BaseUrl = new Uri(String.Format(wadoPrefix, host, wadoPort)); } catch (FormatException ex) { // this exception happens if the FormatWadoUriPrefix setting is invalid. throw new Exception(SR.MessageStreamingClientConfigurationException, ex); } AETitle = source.Parent._aeTitle; StudyInstanceUid = source.Parent.StudyInstanceUid; SeriesInstanceUid = source.Parent.SeriesInstanceUid; SopInstanceUid = source.Parent.SopInstanceUid; FrameNumber = source.FrameNumber; TransferSyntaxUid = source.Parent.TransferSyntaxUid; }
private static FramePixelData CreateDiff(FramePixelData a, FramePixelData b) { int minWidth, maxWidth, minHeight, maxHeight; MathUtility.MinMax(a.Width, b.Width, out minWidth, out maxWidth); MathUtility.MinMax(a.Height, b.Height, out minHeight, out maxHeight); var diff = new FramePixelData(maxWidth, maxHeight); for (var y = 0; y < minHeight; ++y) { var indexA = y * a.Width; var indexB = y * b.Width; var indexDiff = y * diff.Width; for (var x = 0; x < minWidth; ++x) { // Ignore alpha. If alpha diffs are // needed, a special strategy will have // to be devised, since XOR'ing two // opaque pixels will cause a totally // transparent pixel and hide any other // difference. diff.Data [indexDiff] = new Color( (byte)(a.Data [indexA].R ^ b.Data [indexB].R), (byte)(a.Data [indexA].G ^ b.Data [indexB].G), (byte)(a.Data [indexA].B ^ b.Data [indexB].B)); indexA++; indexB++; indexDiff++; } } return(diff); }
public StreamingSopFrameData(int frameNumber, StreamingSopDataSource parent) : base(frameNumber, parent, LargeObjectContainerData.PresetNetworkLoadedData) { _framePixelData = new FramePixelData(this.Parent, frameNumber); _overlayData = new byte[16][]; }
private static void Normalize (FramePixelData frame) { Color max = new Color(0, 0, 0, 0); foreach (var pixel in frame.Data) { max.B = Math.Max (pixel.B, max.B); max.G = Math.Max (pixel.G, max.G); max.R = Math.Max (pixel.R, max.R); max.A = Math.Max (pixel.A, max.A); } if (max.B == 0) max.B = 255; if (max.G == 0) max.G = 255; if (max.R == 0) max.R = 255; if (max.A == 0) max.A = 255; for (int i = 0; i < frame.Data.Length; ++i) { Color pixel = frame.Data[i]; pixel.B = (byte)(pixel.B * 255 / max.B); pixel.G = (byte)(pixel.G * 255 / max.G); pixel.R = (byte)(pixel.R * 255 / max.R); pixel.A = (byte)(pixel.A * 255 / max.A); frame.Data[i] = pixel; } }
private static FramePixelData CreateDiff (FramePixelData a, FramePixelData b) { int minWidth, maxWidth, minHeight, maxHeight; MathUtility.MinMax (a.Width, b.Width, out minWidth, out maxWidth); MathUtility.MinMax (a.Height, b.Height, out minHeight, out maxHeight); var diff = new FramePixelData (maxWidth, maxHeight); for (int y = 0; y < minHeight; ++y) { int indexA = y * a.Width; int indexB = y * b.Width; int indexDiff = y * diff.Width; for (int x = 0; x < minWidth; ++x) { // Ignore alpha. If alpha diffs are // needed, a special strategy will have // to be devised, since XOR'ing two // opaque pixels will cause a totally // transparent pixel and hide any other // difference. diff.Data [indexDiff] = new Color ( (byte) (a.Data [indexA].R ^ b.Data [indexB].R), (byte) (a.Data [indexA].G ^ b.Data [indexB].G), (byte) (a.Data [indexA].B ^ b.Data [indexB].B)); indexA++; indexB++; indexDiff++; } } return diff; }
public float Compare(FramePixelData a, FramePixelData b) { return(_value); }
protected void CheckFrames() { if (!_framePrepared) { throw new Exception("PrepareFrameCapture must be called before rendering to be able to check frames."); } // submit the current frame if one is prepared, but none are submitted yet if (!_frameSubmitted) { SubmitFrame(); } var folderName = TestContext.CurrentContext.GetTestFolderName(); var referenceImageDirectory = Paths.ReferenceImage(folderName); var outputDirectory = Paths.CapturedFrame(folderName); var fileName = TestContext.CurrentContext.GetTestFrameFileNameFormat(_totalFramesExpected); var capturedImagePath = Path.Combine(outputDirectory, fileName); var referenceImagePath = Path.Combine(referenceImageDirectory, fileName); var allResults = new List <FrameComparisonResult>(); var failedResults = new List <FrameComparisonResult>(); var noReference = new List <string>(); for (var i = 0; i < _submittedFrames.Count; i++) { var frame = _submittedFrames[i]; var capturedPath = string.Format(capturedImagePath, i + 1); var referencePath = string.Format(referenceImagePath, i + 1); if (!File.Exists(referencePath)) { // no reference frame is available, so just write the image and track the failure if (WriteCapture == WriteSettings.Always || WriteCapture == WriteSettings.WhenFailed) { Directory.CreateDirectory(outputDirectory); _writerThread.AddAction(() => frame.Save(capturedPath)); } noReference.Add(referencePath); continue; } var refFrame = FramePixelData.FromFile(referencePath); var frameSimilarity = _frameComparer.Compare(frame, refFrame); var failed = frameSimilarity < Similarity; var writeCapture = WriteCapture == WriteSettings.Always || (WriteCapture == WriteSettings.WhenFailed && failed); var writeDiff = WriteDiffs == WriteSettings.Always || (WriteDiffs == WriteSettings.WhenFailed && failed); var result = new FrameComparisonResult(frameSimilarity, frame, refFrame, capturedPath, referencePath, failed, writeCapture, writeDiff); allResults.Add(result); if (failed) { failedResults.Add(result); } if (result.SaveImage) { Directory.CreateDirectory(outputDirectory); _writerThread.AddAction(() => result.CapturedData.Save(result.CapturedImagePath)); } if (result.SaveDiff) { var name = string.Format(fileName, i + 1); var path = GetDiffPath(name); result.DiffPath = path; Directory.CreateDirectory(Path.GetDirectoryName(path)); _writerThread.AddAction(() => WriteDiff(result.CapturedData, result.ReferenceData, path)); } } _framesChecked = true; // write results to console WriteComparisonResultReport(allResults, noReference); // wait for the writing thread so it doesn't get terminated early if (!_writerThread.Finished) { _writerThread.Thread.Join(); } // now do the actual assertions if (ExactNumberSubmits && _totalFramesExpected != allResults.Count) { Assert.Fail( "Expected {0} frame comparison result(s), but found {1}", _totalFramesExpected, allResults.Count); } if (failedResults.Count > 0) { Assert.Fail( "{0} of {1} frames failed the similarity test.", failedResults.Count, allResults.Count); } if (noReference.Count > 0) { Assert.Fail( "Did not find reference image(s): " + noReference.Aggregate((s1, s2) => s1 + ", " + s2)); } }
public StreamingSopFrameData(int frameNumber, StreamingSopDataSource parent) : base(frameNumber, parent, RegenerationCost.High) { _framePixelData = new FramePixelData(this.Parent, frameNumber); _overlayData = new byte[16][]; }