public WhenReduceDestArea() { _mapBuilder = new Area2DMapBuilder(); _sourceArea = Area2D.Create(0, 0, 10, 10); _destArea = Area2D.Create(0, 0, 10, 10); }
public WhenSetIgnoredSourcedArea() { _mapBuilder = new Area2DMapBuilder(); _sourceArea = Area2D.Create(0, 0, 10, 10); _destArea = Area2D.Create(0, 0, 10, 10); }
public WhenAddAssociatedAreas() { _mapBuilder = new Area2DMapBuilder(); _sourceArea = Area2D.Create(0, 0, 10, 10); _destArea = Area2D.Create(0, 0, 10, 10); }
public PmData(ZsImage destImage, ZsImage srcImage) { if (destImage == null) { throw new ArgumentNullException(nameof(destImage)); } if (srcImage == null) { throw new ArgumentNullException(nameof(srcImage)); } DestImage = destImage; SrcImage = srcImage; Nnf = new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height); Settings = new PatchMatchSettings(); var destImageArea = Area2D.Create(0, 0, destImage.Width, destImage.Height); DestImagePixelsArea = destImageArea; var mapBuilder = new Area2DMapBuilder(); mapBuilder.InitNewMap( destImageArea, Area2D.Create(0, 0, srcImage.Width, srcImage.Height)); Map = mapBuilder.Build(); }
public WhenInitNewMap() { _mapBuilder = new Area2DMapBuilder(); _emptyArea = Area2D.Empty; _sourceArea = Area2D.Create(0, 0, 10, 10); _destArea = Area2D.Create(0, 0, 10, 10); }
protected static Area2DMap CreateMapping(int x, int y, int w, int h) { var builder = new Area2DMapBuilder(); builder.InitNewMap(Area2D.Create(x, y, w, h), Area2D.Create(x, y, w, h)); var mapping = builder.Build(); return(mapping); }
static void Main(string[] args) { const string basePath = "..\\..\\..\\images"; var destImageName = "pm2small.png"; var srcImageName = "pm1small.png"; var emptyAreaImageName = "pm2small_ignore.png"; // This is our input data. var destImage = GetLabImage(basePath, destImageName); var srcImage = GetLabImage(basePath, srcImageName); var destArea = Area2D.Create(0, 0, destImage.Width, destImage.Height); var srcArea = Area2D.Create(0, 0, srcImage.Width, srcImage.Height); var emptyArea = GetArea2D(basePath, emptyAreaImageName); var destPixelsArea = destArea.Substract(emptyArea); var map = new Area2DMapBuilder() .InitNewMap(destArea, srcArea) .Build(); const byte patchSize = 5; var settings = new PatchMatchSettings { PatchSize = patchSize }; var nnf = new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height, patchSize); var calculator = ImagePatchDistance.Cie76; var patchMatchNnfBuilder = new PatchMatchNnfBuilder(); // Create the nnf the images // with a couple of iterations. patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf, destImage, srcImage, settings, calculator, map, destPixelsArea); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map, destPixelsArea); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map, destPixelsArea); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map, destPixelsArea); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map, destPixelsArea); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map, destPixelsArea); // Restore dest image from the NNF and source image. nnf .RestoreImage(srcImage, 3, settings.PatchSize) .FromLabToRgb() .FromRgbToBitmap() .SaveTo(@"..\..\restored.png", ImageFormat.Png); // Convert the NNF to an image, save and show it nnf .ToRgbImage() .FromRgbToBitmap() .SaveTo(@"..\..\nnf.png", ImageFormat.Png) .ShowFile(); Console.WriteLine($"PatchMatchPipeline processing is finished."); }
public WhenAddMapping() { _mapBuilder = new Area2DMapBuilder(); _sourceArea = Area2D.Create(0, 0, 10, 10); _destArea = Area2D.Create(0, 0, 10, 10); _mapping = _mapBuilder.InitNewMap(_destArea, _sourceArea) .Build(); _mapBuilder = new Area2DMapBuilder(); }
public WhenBuild() { _mapBuilder = new Area2DMapBuilder(); _emptyArea = Area2D.Empty; _sourceArea = Area2D.Create(10, 10, 10, 10); _destArea = Area2D.Create(0, 0, 10, 10); var areas = new[] { new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), Area2D.Create(3, 3, 5, 5)), new Tuple <Area2D, Area2D>(Area2D.Create(5, 0, 5, 5), Area2D.Create(0, 0, 10, 10)), new Tuple <Area2D, Area2D>(Area2D.Create(0, 5, 5, 5), Area2D.Create(5, 2, 6, 6)), new Tuple <Area2D, Area2D>(Area2D.Create(5, 5, 5, 5), Area2D.Create(0, 2, 8, 6)), }; _initialMapping = new Area2DMap(areas, _emptyArea); }
/// <summary> /// Runs the random NNF initialization iteration using the whole areas of the dest and the source images. /// </summary> /// <param name="nnf">The NNF.</param> /// <param name="destImage">The dest image. For each patch at this image we will look for a similar one at the source image.</param> /// <param name="srcImage">The source image. Source of the patches for the dest image.</param> /// <param name="settings">The settings that control parameters of the algorithm.</param> /// <param name="patchDistanceCalculator">The calculator that calculates similarity of two patches. By deafult the Cie76 is used.</param> /// <exception cref="ArgumentNullException"> /// destImage /// or /// srcImage /// </exception> public void RunRandomNnfInitIteration(Nnf nnf, ZsImage destImage, ZsImage srcImage, PatchMatchSettings settings, ImagePatchDistanceCalculator patchDistanceCalculator) { if (destImage == null) { throw new ArgumentNullException(nameof(destImage)); } if (srcImage == null) { throw new ArgumentNullException(nameof(srcImage)); } var destArea = Area2D.Create(0, 0, destImage.Width, destImage.Height); var srcArea = Area2D.Create(0, 0, srcImage.Width, srcImage.Height); var map = new Area2DMapBuilder() .InitNewMap(destArea, srcArea) .Build(); RunRandomNnfInitIteration(nnf, destImage, srcImage, settings, patchDistanceCalculator, map); }
/// <summary> /// Clones the NNF and scales it up 2 times with distances recalculation. /// </summary> /// <param name="nnf">The NNF.</param> /// <param name="scaledDestImage">The scaled dest image.</param> /// <param name="scaledSrcImage">The scaled source image.</param> /// <param name="options">The options for parallel processing.</param> /// <param name="patchDistanceCalculator">The calculator that calculates similarity of two patches. By deafult the Cie76 is used.</param> /// <param name="destPixelsArea">Area on the dest image that actually containes pixels. By default is the area of the entire image.</param> /// <returns></returns> /// <exception cref="ArgumentNullException"> /// nnf /// or /// scaledDestImage /// or /// scaledSrcImage /// </exception> public static Nnf CloneAndScale2XWithUpdate(this Nnf nnf, ZsImage scaledDestImage, ZsImage scaledSrcImage, ParallelOptions options = null, ImagePatchDistanceCalculator patchDistanceCalculator = null, Area2D destPixelsArea = null) { if (scaledDestImage == null) { throw new ArgumentNullException(nameof(scaledDestImage)); } if (scaledSrcImage == null) { throw new ArgumentNullException(nameof(scaledSrcImage)); } var destArea = Area2D.Create(0, 0, scaledDestImage.Width, scaledDestImage.Height); var srcArea = Area2D.Create(0, 0, scaledSrcImage.Width, scaledSrcImage.Height); Area2DMap scaledMap = new Area2DMapBuilder() .InitNewMap(destArea, srcArea) .Build(); return(nnf.CloneAndScale2XWithUpdate(scaledDestImage, scaledSrcImage, options, scaledMap, patchDistanceCalculator, destPixelsArea)); }
private static IEnumerable<Area2DMap> SplitMapping(Area2DMap currentMap, int maxPointsPerProcess, byte patchSize) { // The input should be splitted smartly taking into account the input data and settings. var result = new List<Area2DMap>(); if (currentMap.DestElementsCount > maxPointsPerProcess) { // Decide on how many parts we are going to divide input. var partsAmount = (double)currentMap.DestElementsCount / maxPointsPerProcess; if (partsAmount == 1) partsAmount++; // Let's calculate how many rows & columns we are going to have var rect = currentMap.DestBounds; var w = rect.Width; var h = rect.Height; var left = rect.X; var top = rect.Y; var sideSize = Math.Sqrt(maxPointsPerProcess); double cs, rs; if (w > h) { cs = w / sideSize; rs = partsAmount / cs; } else { rs = h / sideSize; cs = partsAmount / rs; } var csfloor = Math.Floor(cs); var columns = (int)(csfloor < cs ? csfloor + 1 : csfloor); var rsfloor = Math.Floor(rs); var rows = (int)(rsfloor < rs ? rsfloor + 1 : rsfloor); // Finally - what is the cell size? var cellWidth = w / columns; var rowHight = h / rows; // Split mapping var newMappings = new List<Area2DMap>(); for (var y = top; y < top + h; y += rowHight) { for (var x = left; x < left + w; x += cellWidth) { // we extend cell in all direction // so that it overlaps with other cells var cx = Math.Max(x - patchSize, 0); var cy = Math.Max(y - patchSize, 0); var cw = (x - cx) + cellWidth + patchSize; var ch = (y - cy) + rowHight + patchSize; var map = new Area2DMapBuilder() .InitNewMap(currentMap) .ReduceDestArea(Area2D.Create(cx, cy, cw, ch), true) .Build(); if (map.DestElementsCount > 0) { newMappings.Add(map); } } } // Combine small mappings var bins = BinsPacker<Area2DMap>.Pack(newMappings, m => m.DestElementsCount, maxPointsPerProcess); newMappings.Clear(); foreach (var bin in bins) { var enumerable = bin as IList<Area2DMap> ?? bin.ToList(); if (enumerable.Count > 1) { newMappings.Add( enumerable.Aggregate((m1, m2) => new Area2DMapBuilder() .InitNewMap(m1) .AddMapping(m2) .Build())); } else { newMappings.Add(enumerable.First()); } } // Make a new input. for (int i = 0; i < newMappings.Count; i++) { var map = newMappings[i]; if (map.DestElementsCount > 0) { result.Add(map); } } } else { result.Add(currentMap); } return result; }
/// <summary> /// Clones the NNF and scales it up 2 times without distances recalculation. /// </summary> /// <param name="nnf">The NNF.</param> /// <param name="scaledDestImage">The scaled dest image.</param> /// <param name="scaledSrcImage">The scaled source image.</param> /// <param name="options">The options for parallel processing.</param> /// <param name="scaledMap">The areas mapping. By default whole area of the dest image is associated with the whole area of the source image.</param> /// <returns></returns> /// <exception cref="ArgumentNullException"> /// nnf /// or /// scaledDestImage /// or /// scaledSrcImage /// </exception> public static Nnf CloneAndScaleNnf2X(this Nnf nnf, ZsImage scaledDestImage, ZsImage scaledSrcImage, ParallelOptions options = null, Area2DMap scaledMap = null) { if (nnf == null) { throw new ArgumentNullException(nameof(nnf)); } if (scaledDestImage == null) { throw new ArgumentNullException(nameof(scaledDestImage)); } if (scaledSrcImage == null) { throw new ArgumentNullException(nameof(scaledSrcImage)); } if (scaledMap == null) { var destArea = Area2D.Create(0, 0, scaledDestImage.Width, scaledDestImage.Height); var srcArea = Area2D.Create(0, 0, scaledSrcImage.Width, scaledSrcImage.Height); scaledMap = new Area2DMapBuilder() .InitNewMap(destArea, srcArea) .Build(); } if (options == null) { options = new ParallelOptions(); } var destImageWidth = scaledDestImage.Width; var srcImageWidth = scaledSrcImage.Width; var sameSrcAndDest = scaledDestImage == scaledSrcImage; var mappings = scaledMap.ExtractMappedAreasInfo(destImageWidth, srcImageWidth, true); var nnf2x = new Nnf(nnf.DstWidth * 2, nnf.DstHeight * 2, nnf.SourceWidth * 2, nnf.SourceHeight * 2, nnf.PatchSize); var nnfDestWidth = nnf.DstWidth; var nnfSourceWidth = nnf.SourceWidth; var nnf2xSourceWidth = nnf2x.SourceWidth; var nnf2xDstWidth = nnf2x.DstWidth; var nnfData = nnf.GetNnfItems(); var nnf2xData = nnf2x.GetNnfItems(); // Decide on how many partitions we should divade the processing // of the elements. int nnfPointsAmount = nnf.DstWidth * nnf.DstHeight; var partsCount = nnfPointsAmount > options.NotDividableMinAmountElements ? options.ThreadsCount : 1; var partSize = nnfPointsAmount / partsCount; var offs = new[] { new[] { 0, 0 }, new[] { 1, 0 }, new[] { 0, 1 }, new[] { 1, 1 } }; Parallel.For(0, partsCount, partIndex => //for (int partIndex = 0; partIndex < partsCount; partIndex++) { bool isPatchFit = false; var mappedAreasInfos = new MappedAreasInfo[mappings.Length]; for (var i = 0; i < mappings.Length; i++) { mappedAreasInfos[i] = mappings[i].Clone(); } var firstPointIndex = partIndex * partSize; var lastPointIndex = firstPointIndex + partSize - 1; if (partIndex == partsCount - 1) { lastPointIndex = nnfPointsAmount - 1; } if (lastPointIndex > nnfPointsAmount) { lastPointIndex = nnfPointsAmount - 1; } MappedAreasInfo mappedAreasInfo = null; for (var j = firstPointIndex; j <= lastPointIndex; j++) { var destPx = j; var destX = destPx % nnfDestWidth; var destY = destPx / nnfDestWidth; // Find var srcPointIndex = nnfData[destY * nnfDestWidth * 2 + destX * 2]; // / 2; int srcY = (int)(srcPointIndex / nnfSourceWidth); // * 2; int srcX = (int)(srcPointIndex % nnfSourceWidth); // * 2; var dist = nnfData[destY * nnfDestWidth * 2 + destX * 2 + 1]; var nY = destY * 2; var nX = destX * 2; for (int i = 0; i < offs.Length; i++) { var destPointIndex = (nY + offs[i][1]) * nnf2xDstWidth + nX + offs[i][0]; mappedAreasInfo = mappedAreasInfos.FirstOrDefault(mai => mai.DestAreaPointsIndexesSet.Contains(destPointIndex)); if (mappedAreasInfo != null) { nnf2xData[destPointIndex * 2] = (srcY * 2 + offs[i][1]) * nnf2xSourceWidth + (srcX * 2 + offs[i][0]); nnf2xData[destPointIndex * 2 + 1] = dist; } else { if (sameSrcAndDest) { // when the source and the dest image is the same one, the best // corresponding patch is the patch itself! nnf2xData[destPointIndex * 2] = destPointIndex; nnf2xData[destPointIndex * 2 + 1] = 0; } else { nnf2xData[destPointIndex * 2] = (srcY * 2 + offs[i][1]) * nnf2xSourceWidth + (srcX * 2 + offs[i][0]); nnf2xData[destPointIndex * 2 + 1] = nnfData[destY * nnfDestWidth * 2 + destX * 2 + 1]; } } } } } ); return(nnf2x); }
static void Main(string[] args) { const string basePath = "..\\..\\..\\..\\images"; const int patchSize = 5; var srcImageName = "t009.jpg"; // Prepare images var srcImage = GetLabImage(basePath, srcImageName); var destImage = GetLabImage(basePath, srcImageName); var ignoreArea = GetArea2D(basePath, "m009.png"); var destArea = ignoreArea.Dilation(patchSize * 2 + 1); // Init an nnf var nnf = new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height, patchSize); // Create a mapping of the areas on the dest and source areas. var imageArea = Area2D.Create(0, 0, srcImage.Width, srcImage.Height); var map = new Area2DMapBuilder() .InitNewMap(imageArea, imageArea) .SetIgnoredSourcedArea(ignoreArea) .Build(); // Prepage setting for the PM algorithm var settings = new PatchMatchSettings { PatchSize = patchSize }; var calculator = ImagePatchDistance.Cie76; var patchMatchNnfBuilder = new PatchMatchNnfBuilder(); // Create the nnf for the image(while ignoring some area) // with a couple of iterations. patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf, destImage, srcImage, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map); // Create a mapping for the area that is a bit bigger // then ignored area. map = new Area2DMapBuilder() .InitNewMap(imageArea, imageArea) .ReduceDestArea(destArea) .SetIgnoredSourcedArea(ignoreArea) .Build(); patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf, destImage, srcImage, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map); string fileName1 = @"..\..\..\nnf1_pure.png"; nnf .ToRgbImage() .FromRgbToBitmap() .SaveTo(fileName1, ImageFormat.Png); // Normalize the NNF in the ignored area. nnf.Normalize(ignoreArea); // Prepare results, save and show them string fileName2 = @"..\..\..\nnf2_normalized.png"; nnf .ToRgbImage() .FromRgbToBitmap() .SaveTo(fileName2, ImageFormat.Png) .ShowFile(); Console.WriteLine($"Nnf normalization is finished."); }
static void Main(string[] args) { const string basePath = "..\\..\\..\\..\\images"; var destImageName = "pm1.png"; var srcImageName = "pm2.png"; var destArea1ImageName = "pm1_target1.png"; var destArea2ImageName = "pm1_target2.png"; // this is our input data. var destImage = GetLabImage(basePath, destImageName); var srcImage = GetLabImage(basePath, srcImageName); var destArea1 = GetArea2D(basePath, destArea1ImageName); var destArea2 = GetArea2D(basePath, destArea2ImageName); var srcArea = Area2D.Create(0, 0, srcImage.Width, srcImage.Height); var map1 = new Area2DMapBuilder() .InitNewMap(destArea1, srcArea) .Build(); var map2 = new Area2DMapBuilder() .InitNewMap(destArea2, srcArea) .Build(); var settings = new PatchMatchSettings { PatchSize = 5 }; var patchMatchNnfBuilder = new PatchMatchNnfBuilder(); var calculator = ImagePatchDistance.Cie76; // Create nnf for the images // with a couple of iterations. var nnf1 = new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height, settings.PatchSize); patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf1, destImage, srcImage, settings, calculator, map1); patchMatchNnfBuilder.RunBuildNnfIteration(nnf1, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map1); patchMatchNnfBuilder.RunBuildNnfIteration(nnf1, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map1); patchMatchNnfBuilder.RunBuildNnfIteration(nnf1, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map1); patchMatchNnfBuilder.RunBuildNnfIteration(nnf1, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map1); patchMatchNnfBuilder.RunBuildNnfIteration(nnf1, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map1); // Create the nnf for the images // with a couple of iterations. var nnf2 = new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height, settings.PatchSize); patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf2, destImage, srcImage, settings, calculator, map2); patchMatchNnfBuilder.RunBuildNnfIteration(nnf2, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map2); patchMatchNnfBuilder.RunBuildNnfIteration(nnf2, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map2); patchMatchNnfBuilder.RunBuildNnfIteration(nnf2, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map2); patchMatchNnfBuilder.RunBuildNnfIteration(nnf2, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map2); patchMatchNnfBuilder.RunBuildNnfIteration(nnf2, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map2); // Show the built NNFs and restored images nnf2 .RestoreImage(srcImage, 3, settings.PatchSize) .FromLabToRgb() .FromRgbToBitmap() .SaveTo(@"..\..\..\restored1.png", ImageFormat.Png); nnf1 .RestoreImage(srcImage, 3, settings.PatchSize) .FromLabToRgb() .FromRgbToBitmap() .SaveTo(@"..\..\..\restored2.png", ImageFormat.Png); nnf1 .ToRgbImage() .FromRgbToBitmap() .SaveTo(@"..\..\..\nnf1.png", ImageFormat.Png); nnf2 .ToRgbImage() .FromRgbToBitmap() .SaveTo(@"..\..\..\nnf2.png", ImageFormat.Png); // Let's now merge the built NNFs and try to restore an image nnf2.Merge(nnf1, map2, map1); nnf2 .RestoreImage(srcImage, 3, settings.PatchSize) .FromLabToRgb() .FromRgbToBitmap() .SaveTo(@"..\..\..\restored_whole.png", ImageFormat.Png); nnf2 .ToRgbImage() .FromRgbToBitmap() .SaveTo(@"..\..\..\merged_nnf.png", ImageFormat.Png) .ShowFile(); Console.WriteLine($"PatchMatchPipeline processing is finished."); }
static void Main(string[] args) { var sw = new Stopwatch(); sw.Start(); const string basePath = "..\\..\\..\\..\\images"; var destImageName = "pm1.png"; var srcImageName = "pm2.png"; var destTargetImageName = "dd1.png"; // this is our input data. var destImage = GetLabImage(basePath, destImageName); var srcImage = GetLabImage(basePath, srcImageName); var destTargetArea1 = GetArea2D(basePath, destTargetImageName); var srcArea1 = GetArea2D(basePath, "sd1.png"); var destArea2 = GetArea2D(basePath, "dd2.png"); var srcArea2 = GetArea2D(basePath, "sd2.png"); var destArea = Area2D.Create(0, 0, destImage.Width, destImage.Height); var srcArea = Area2D.Create(0, 0, srcImage.Width, srcImage.Height); var map = new Area2DMapBuilder() .InitNewMap(destArea, srcArea) .AddAssociatedAreas(destTargetArea1, srcArea1) .AddAssociatedAreas(destArea2, srcArea2) .Build(); const byte patchSize = 5; var nnf = new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height, patchSize); // Prepage setting for the PM algorithm var settings = new PatchMatchSettings { PatchSize = patchSize }; var calculator = ImagePatchDistance.Cie76; var patchMatchNnfBuilder = new PatchMatchNnfBuilder(); // Create the nnf for the small variant of the images // with a couple of iterations. patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf, destImage, srcImage, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Backward, settings, calculator, map); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings, calculator, map); // Restore dest image from the NNF and source image. nnf .RestoreImage(srcImage, 3, patchSize) .FromLabToRgb() .FromRgbToBitmap() .SaveTo(@"..\..\..\restored.png", ImageFormat.Png); // Convert the NNF to an image, save and show it nnf .ToRgbImage() .FromRgbToBitmap() .SaveTo(@"..\..\..\nnf.png", ImageFormat.Png) .ShowFile(); sw.Stop(); Console.WriteLine($"Elapsed time: {sw.Elapsed}"); Console.WriteLine($"PatchMatchPipeline processing is finished."); }