예제 #1
0
        /// <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));
        }
예제 #2
0
        public static async Task ScaleNnf([ActivityTrigger] NnfInputData input)
        {
            var container = BlobHelper.OpenBlobContainer(input.Container);
            var imageBlob = container.GetBlockBlobReference(input.Image);
            var image     = (await BlobHelper.ConvertBlobToArgbImage(imageBlob))
                            .FromArgbToRgb(new[] { 0.0, 0.0, 0.0 })
                            .FromRgbToLab();

            var calculator = input.IsCie79Calc
                ? ImagePatchDistance.Cie76
                : ImagePatchDistance.Cie2000;

            var mappingState = BlobHelper.ReadFromBlob <Area2DMapState>(input.Mapping, container);
            var mapping      = new Area2DMap(mappingState);

            var nnfState = BlobHelper.ReadFromBlob <NnfState>($"nnf{input.LevelIndex - 1}.json", container);
            var nnf      = new Nnf(nnfState);

            nnf = nnf.CloneAndScale2XWithUpdate(image, image, input.Settings.PatchMatch, mapping, calculator);

            var nnfData = JsonConvert.SerializeObject(nnf.GetState());

            BlobHelper.SaveJsonToBlob(nnfData, container, input.NnfName);
        }
예제 #3
0
        static void Main(string[] args)
        {
            const string basePath      = "..\\..\\..\\images";
            const string srcImageName  = "pm1.png";
            const string destImageName = "pm2.png";
            const int    patchSize     = 5;

            // Prepare 2 source images - one small and another 2x bigger
            var srcBitmap = new Bitmap(Path.Combine(basePath, srcImageName));
            var srcImage  = srcBitmap
                            .ToRgbImage()
                            .FromRgbToLab();

            var srcSmallBitmap = srcBitmap.CloneWithScaleTo(srcBitmap.Width / 2, srcBitmap.Height / 2);
            var srcSmallImage  = srcSmallBitmap
                                 .ToRgbImage()
                                 .FromRgbToLab();

            srcSmallBitmap.Dispose();
            srcBitmap.Dispose();

            var destBitmap = new Bitmap(Path.Combine(basePath, destImageName));
            var destImage  = destBitmap
                             .ToRgbImage()
                             .FromRgbToLab();

            var destSmallBitmap = destBitmap.CloneWithScaleTo(destBitmap.Width / 2, destBitmap.Height / 2);
            var destSmallImage  = destSmallBitmap
                                  .ToRgbImage()
                                  .FromRgbToLab();

            destBitmap.Dispose();
            destSmallBitmap.Dispose();

            // Init an nnf
            var nnf = new Nnf(destSmallImage.Width, destSmallImage.Height, srcSmallImage.Width, srcSmallImage.Height, patchSize);

            // Prepage setting for the PM algorithm
            var settings = new PatchMatchSettings {
                PatchSize = patchSize
            };
            var patchMatchNnfBuilder = new PatchMatchNnfBuilder();

            // Create the nnf for the small variant of the images
            // with a couple of iterations.
            patchMatchNnfBuilder.RunRandomNnfInitIteration(nnf, destSmallImage, srcSmallImage, settings);
            patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destSmallImage, srcSmallImage, NeighboursCheckDirection.Backward, settings);
            patchMatchNnfBuilder.RunBuildNnfIteration(nnf, destSmallImage, srcSmallImage, NeighboursCheckDirection.Forward, settings);

            // The scaling of the NNF from the small images to the bigger ones.
            var scaledNnf = nnf.CloneAndScale2XWithUpdate(destImage, srcImage, settings);

            // Prepare results, save and show them
            scaledNnf
            .RestoreImage(srcImage, 3, patchSize)
            .FromLabToRgb()
            .FromRgbToBitmap()
            .SaveTo(@"..\..\l2r.png", ImageFormat.Png);

            scaledNnf
            .ToRgbImage()
            .FromRgbToBitmap()
            .SaveTo(@"..\..\l2n.png", ImageFormat.Png)
            .ShowFile();

            Console.WriteLine($"NnfScaleUp processing is finished.");
        }
예제 #4
0
        private ZsImage InternalInpaint(Pyramid pyramid, InpaintSettings settings)
        {
            #region cache settings
            var patchSize   = settings.PatchSize;
            var calculator  = settings.PatchDistanceCalculator;
            var nnfSettings = settings.PatchMatch;
            var changedPixelsPercentTreshold = settings.ChangedPixelsPercentTreshold;
            var maxInpaintIterationsAmount   = settings.MaxInpaintIterations;
            var kStep = settings.MeanShift.KDecreaseStep;
            var minK  = settings.MeanShift.MinK;
            #endregion

            ZsImage image = null;

            // go thru all the pyramid levels starting from the top one
            Nnf nnf = null;

            for (byte levelIndex = 0; levelIndex < pyramid.LevelsAmount; levelIndex++)
            {
                image = pyramid.GetImage(levelIndex);
                var mapping     = pyramid.GetMapping(levelIndex);
                var inpaintArea = pyramid.GetInpaintArea(levelIndex);

                var imageArea = Area2D.Create(0, 0, image.Width, image.Height);

                // if there is a NNF built on the prev level
                // scale it up
                nnf = nnf == null
                    ? new Nnf(image.Width, image.Height, image.Width, image.Height, patchSize)
                    : nnf.CloneAndScale2XWithUpdate(image, image, nnfSettings, mapping, calculator);

                // start inpaint iterations
                var k = settings.MeanShift.K;
                for (var inpaintIterationIndex = 0; inpaintIterationIndex < maxInpaintIterationsAmount; inpaintIterationIndex++)
                {
                    // Obtain pixels area.
                    // Pixels area defines which pixels are allowed to be used
                    // for the patches distance calculation. We must avoid pixels
                    // that we want to inpaint. That is why before the area is not
                    // inpainted - we should exclude this area.
                    var pixelsArea = imageArea;
                    if (levelIndex == 0 && inpaintIterationIndex == 0 && settings.IgnoreInpaintedPixelsOnFirstIteration)
                    {
                        pixelsArea = imageArea.Substract(inpaintArea);
                    }

                    // skip building NNF for the first iteration in the level
                    // unless it is top level (for the top one we haven't built NNF yet)
                    if (levelIndex == 0 || inpaintIterationIndex > 0)
                    {
                        // in order to find best matches for the inpainted area,
                        // we build NNF for this image as a dest and a source
                        // but excluding the inpainted area from the source area
                        // (our mapping already takes care of it)
                        _nnfBuilder.RunRandomNnfInitIteration(nnf, image, image, nnfSettings, calculator, mapping, pixelsArea);
                        _nnfBuilder.RunBuildNnfIteration(nnf, image, image, NeighboursCheckDirection.Forward, nnfSettings, calculator, mapping, pixelsArea);
                        _nnfBuilder.RunBuildNnfIteration(nnf, image, image, NeighboursCheckDirection.Backward, nnfSettings, calculator, mapping, pixelsArea);
                        _nnfBuilder.RunBuildNnfIteration(nnf, image, image, NeighboursCheckDirection.Forward, nnfSettings, calculator, mapping, pixelsArea);
                        _nnfBuilder.RunBuildNnfIteration(nnf, image, image, NeighboursCheckDirection.Backward, nnfSettings, calculator, mapping, pixelsArea);
                        _nnfBuilder.RunBuildNnfIteration(nnf, image, image, NeighboursCheckDirection.Forward, nnfSettings, calculator, mapping, pixelsArea);
                    }

                    var nnfNormalized = nnf.Clone();
                    nnfNormalized.Normalize();

                    // after we have the NNF - we calculate the values of the pixels in the inpainted area
                    var inpaintResult = Inpaint(image, inpaintArea, nnfNormalized, k, settings);
                    k = k > minK ? k - kStep : k;

                    if (IterationFinished != null)
                    {
                        var eventArgs = new InpaintIterationFinishedEventArgs
                        {
                            InpaintedLabImage = image.Clone(),
                            InpaintResult     = inpaintResult,
                            LevelIndex        = levelIndex,
                            InpaintIteration  = inpaintIterationIndex
                        };
                        IterationFinished(this, eventArgs);
                    }

                    // if the change is smaller then a treshold, we quit
                    if (inpaintResult.ChangedPixelsPercent < changedPixelsPercentTreshold)
                    {
                        break;
                    }
                    //if (levelIndex == pyramid.LevelsAmount - 1) break;
                }
            }

            return(image);
        }