private static ZsImage CopyImageArea(ZsImage imageArgb, Area2D imageSrcArea) { var pixels = Enumerable.Repeat(0.0, imageSrcArea.Bound.Width * imageSrcArea.Bound.Height * 4).ToArray(); var resultImage = new ZsImage(pixels, imageSrcArea.Bound.Width, imageSrcArea.Bound.Height, 4); var imageArgbArea = Area2D.Create(0, 0, imageSrcArea.Bound.Width, imageSrcArea.Bound.Height); resultImage.CopyFromImage(imageArgbArea, imageArgb, imageSrcArea); return(resultImage); }
static void Main(string[] args) { const string basePath = "..\\..\\..\\..\\images"; ZsImage srcImage = GetArgbImage(basePath, "t009.jpg"); ZsImage destImage = srcImage.Clone(); var srcMarkup = GetArea2D(basePath, "m009.png"); var destMarkup = srcMarkup.Translate(-300, -30); destImage.CopyFromImage(destMarkup, destImage, srcMarkup); destImage.FromArgbToBitmap() .SaveTo("..\\..\\..\\target.png", ImageFormat.Png); // Prepage setting for the PM algorithm const byte patchSize = 5; var settings = new PatchMatchSettings { PatchSize = patchSize }; // Init an nnf var nnf = new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height, patchSize); srcImage.FromArgbToRgb(new[] { 1.0, 1.0, 1.0 }) .FromRgbToLab(); destImage.FromArgbToRgb(new[] { 1.0, 1.0, 1.0 }) .FromRgbToLab(); destImage .Clone() .FromLabToRgb() .FromRgbToBitmap() .SaveTo($"..\\..\\..\\dest.png", ImageFormat.Png); var patchMatchNnfBuilder = new PatchMatchNnfBuilder(); patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf, destImage, srcImage, settings); for (int j = 0; j < 3; j++) { patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Forward, settings); Console.WriteLine($"\tIteration {j * 2}"); patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destImage, srcImage, NeighboursCheckDirection.Backward, settings); Console.WriteLine($"\tIteration {j * 2 + 1}"); } nnf.ToRgbImage() .FromRgbToBitmap() .SaveTo($"..\\..\\..\\nnf.png", ImageFormat.Png); nnf.RestoreImage(srcImage, 3, patchSize) .FromLabToRgb() .FromRgbToBitmap() .SaveTo($"..\\..\\..\\restored.png", ImageFormat.Png); }
private static ZsImage AlignImage(ZsImage wrongSizedImageArgb, ZsImage correctSizedImageArgb) { var correctArea = Area2D.Create(0, 0, correctSizedImageArgb.Width, correctSizedImageArgb.Height); var wrongArea = Area2D.Create(0, 0, wrongSizedImageArgb.Width, wrongSizedImageArgb.Height); var srcArea = wrongArea.Intersect(correctArea); var pixels = Enumerable.Repeat(0.0, correctSizedImageArgb.Width * correctSizedImageArgb.Height * 4).ToArray(); var correctedImage = new ZsImage(pixels, correctSizedImageArgb.Width, correctSizedImageArgb.Height, 4); return(correctedImage.CopyFromImage(correctArea, wrongSizedImageArgb, srcArea)); }
public ZsImage Inpaint(ZsImage imageArgb, ZsImage markupArgb, InpaintSettings settings, IEnumerable <ZsImage> donorsArgb = null) { #region validate the inputs if (imageArgb == null) { throw new ArgumentNullException(nameof(imageArgb)); } if (imageArgb.NumberOfComponents != 4) { throw new BadImageFormatException($"{nameof(imageArgb)} is expected to be in ARGB format"); } if (markupArgb == null) { throw new ArgumentNullException(nameof(markupArgb)); } if (markupArgb.NumberOfComponents != 4) { throw new BadImageFormatException($"{nameof(markupArgb)} is expected to be in ARGB format"); } if (settings == null) { throw new ArgumentNullException(nameof(settings)); } if (donorsArgb == null) { donorsArgb = new ZsImage[0]; } else if (donorsArgb.Any(donorArgb => donorArgb.NumberOfComponents != 4)) { throw new BadImageFormatException($"{nameof(donorsArgb)} are expected to be in ARGB format"); } #endregion // Prepare input data var originalImageArea = Area2D.Create(0, 0, imageArgb.Width, imageArgb.Height); ZsImage imageToPorcess; Pyramid imagePyramid; var levelsAmount = _levelDetector.CalculateLevelsAmount(imageArgb, markupArgb, settings.PatchSize); // Get the area of the image that can be scaled down required amount of times (levels) var areaToProcess = GetImageAreaToProcess(imageArgb, markupArgb, levelsAmount); if (!areaToProcess.IsSameAs(originalImageArea)) { // We need to crop the original image, markup and donors // since the area to process differs from the image area imageToPorcess = CopyImageArea(imageArgb, areaToProcess); var markup = CopyImageArea(markupArgb, areaToProcess); var donors = donorsArgb.Select(donorImage => CopyImageArea(donorImage, areaToProcess)); imagePyramid = BuildPyramid(imageToPorcess, markup, donors, levelsAmount, settings.PatchSize); } else { imageToPorcess = imageArgb.Clone(); imagePyramid = BuildPyramid(imageToPorcess, markupArgb, donorsArgb, levelsAmount, settings.PatchSize); } imageToPorcess = InternalInpaint(imagePyramid, settings); // paste result in the original bitmap where it was extracted from var imageArea = Area2D.Create(0, 0, imageToPorcess.Width, imageToPorcess.Height); imageToPorcess.FromLabToRgb() .FromRgbToArgb(imageArea); imageArgb.CopyFromImage(areaToProcess, imageToPorcess, imageArea); return(imageArgb); }
// [Benchmark] public static void Remove() { const int toRemove = 100; //using (var imageBitmap = new Bitmap(@"..\..\..\images\Valve_original.png")) using (var imageBitmap = new Bitmap(@"..\..\..\images\t001.png")) //using (var protectBitmap = new Bitmap(@"..\..\..\images\p009.png")) using (var removeBitmap = new Bitmap(@"..\..\..\images\m001.png")) //using (var imageBitmap = new Bitmap(@"..\..\..\images\sc1.png")) { var imageArea = Area2D.Create(0, 0, imageBitmap.Width, imageBitmap.Height); var protectArea = Area2D.Empty;// protectBitmap.ToArea(); var removeArea = removeBitmap.ToArea(); // TODO: Sobel in one go var filterX = new double[] { +1, 0, -1, +2, 0, -2, +1, 0, -1 }; var filterY = new double[] { +1, +2, +1, 0, 0, 0, -1, -2, -1 }; var image1 = imageBitmap .ToRgbImage(); var energyMap = imageBitmap .ToRgbImage() .FromRgbToGray(); var image2 = energyMap.Clone(); // Apply Sobol operator energyMap.Filter(imageArea, filterX, 3, 3); image2.Filter(imageArea, filterY, 3, 3); energyMap.MergeImage(image2); // adjust energy energyMap.NormalizeWeights(energyMap.Height, energyMap.Height * 2, imageArea); //energyMap.NormalizeWeights(0, 1, imageArea); //energyMap.NormalizeWeights(1, 3, imageArea); energyMap.SetComponentsValues(protectArea, new[] { 1.0 }, 0); energyMap.SetComponentsValues(removeArea, new[] { 0.0 }, 0); // build energy map energyMap.ConvertToEnergyMap(imageArea); //energyMap.NormalizeEnergyMap(imageArea); int[] xes = new int[energyMap.Height]; // TODO: while not removed // TODO: Add component to the energy map or image with the markup // TODO: Convert the markup to Area and check whether it was reduced if it is not 3 times in a row - stop. for (int i = 0; i < toRemove; i++) { // find min energy sequence FillMinSequence(xes, energyMap, imageArea); // remove max col / row from photo &energy map Update(energyMap.PixelsData, xes, imageArea, image1.Width, image1.Height, 1); //RemoveSequence(xes, energyMap); RemoveSequence(xes, image1); imageArea = Area2D.Create(imageArea.Bound.X, imageArea.Bound.Y, imageArea.Bound.Width - 1, imageArea.Bound.Height); } // TODO: restor with the protection // TODO: restor without the protection if (true) { var newWidth = image1.Width - toRemove; var pixels = Enumerable.Repeat(0.0, newWidth * image1.Height * image1.NumberOfComponents).ToArray(); var image3 = new ZsImage(pixels, newWidth, image1.Height, image1.NumberOfComponents); var destArea = Area2D.Create(0, 0, image3.Width, image3.Height); var srcArea = Area2D.Create(0, 0, image1.Width, image1.Height); image3 .CopyFromImage(destArea, image1, srcArea) .FromRgbToBitmap() .SaveTo("..\\..\\out2.png", ImageFormat.Png) .ShowFile(); //energyMap.FromGrayToRgb() // .FromRgbToBitmap() // .SaveTo("..\\..\\out1.png", ImageFormat.Png) // .ShowFile(); } } }