예제 #1
0
        private static ZsImage CreateImage(int w, int h, double vals = 1.0)
        {
            var pixels = Enumerable.Repeat(vals, w * h * 4).ToArray();
            var image  = new ZsImage(pixels, w, h, 4);

            return(image);
        }
예제 #2
0
        public PmData(ZsImage destImage, ZsImage srcImage, Nnf nnf, Area2DMap map)
        {
            if (destImage == null)
            {
                throw new ArgumentNullException(nameof(destImage));
            }

            if (srcImage == null)
            {
                throw new ArgumentNullException(nameof(srcImage));
            }

            if (map == null)
            {
                throw new ArgumentNullException(nameof(map));
            }

            if (nnf == null)
            {
                throw new ArgumentNullException(nameof(nnf));
            }

            Map                 = map;
            Nnf                 = nnf;
            DestImage           = destImage;
            SrcImage            = srcImage;
            DestImagePixelsArea = Area2D.Create(0, 0, destImage.Width, destImage.Height);

            Settings = new PatchMatchSettings();
        }
예제 #3
0
        /// <summary>
        /// Runs the NNF build iteration using the whole areas of the dest and the source images. Uses CIE76 to calculate patch similarity.
        /// </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="direction">The direction to look for a patches.</param>
        /// <param name="settings">The settings that control parameters of the algorithm.</param>
        public void RunBuildNnfIteration(Nnf nnf, ZsImage destImage, ZsImage srcImage,
                                         NeighboursCheckDirection direction, PatchMatchSettings settings)
        {
            var patchDistanceCalculator = ImagePatchDistance.Cie76;

            RunBuildNnfIteration(nnf, destImage, srcImage, direction, settings, patchDistanceCalculator);
        }
예제 #4
0
        private static ZsImage Create3pixBiggerMarkupNotEmptyOutsideOfTheImage(int imageWidth, int imageHeight)
        {
            int mw     = imageWidth + 3;
            int mh     = imageHeight + 3;
            var pixels = Enumerable.Repeat <double>(0.0, mw * mh * 4).ToArray();
            var x1     = imageWidth + 0;
            var y1     = imageHeight + 0;

            var x2 = imageWidth + 1;
            var y2 = imageHeight + 1;

            var x3 = imageWidth + 2;
            var y3 = imageHeight + 2;

            pixels[(y1 * mw + x1) * 4 + 0] = 1.0;
            pixels[(y1 * mw + x1) * 4 + 1] = 1.0;
            pixels[(y1 * mw + x1) * 4 + 2] = 1.0;
            pixels[(y2 * mw + x2) * 4 + 0] = 1.0;
            pixels[(y2 * mw + x2) * 4 + 1] = 1.0;
            pixels[(y2 * mw + x2) * 4 + 2] = 1.0;
            pixels[(y3 * mw + x3) * 4 + 0] = 1.0;
            pixels[(y3 * mw + x3) * 4 + 1] = 1.0;
            pixels[(y3 * mw + x3) * 4 + 2] = 1.0;
            var markup = new ZsImage(pixels, mw, mh, 4);

            return(markup);
        }
예제 #5
0
        public void Init(ZsImage imageArgb, ZsImage inpaintMarkupArgb)
        {
            if (imageArgb == null)
            {
                throw new ArgumentNullException(nameof(imageArgb));
            }

            if (inpaintMarkupArgb == null)
            {
                throw new ArgumentNullException(nameof(inpaintMarkupArgb));
            }

            if (imageArgb.NumberOfComponents != 4)
            {
                throw new WrongImageFormatException();
            }

            if (inpaintMarkupArgb.NumberOfComponents != 4)
            {
                throw new WrongImageFormatException();
            }

            _imageArgb     = imageArgb;
            _inpaintMarkup = inpaintMarkupArgb;
            _donors.Clear();
        }
예제 #6
0
 public void AddDonorMarkup(ZsImage donorArgb)
 {
     if (donorArgb != null)
     {
         _donors.Add(donorArgb);
     }
 }
예제 #7
0
        protected static ZsImage CreateImage(int w, int h)
        {
            var pixels = Enumerable.Repeat(0.0, w * h * 4).ToArray();
            var image  = new ZsImage(pixels, w, h, 4);

            return(image);
        }
예제 #8
0
        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();
        }
예제 #9
0
        public void Should_Increase_Stride(double[] pixels, int width, int height, byte componentsAmount,
                                           double[] components, byte position, int result)
        {
            var image = new ZsImage(pixels, width, height, componentsAmount);

            image.InsertComponents(components, position);
            image.Stride.ShouldBe(result);
        }
예제 #10
0
        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);
        }
예제 #11
0
        public static unsafe void MergeImage(this ZsImage grayImage1, ZsImage grayImage2)
        {
            if (grayImage1 == null)
            {
                throw new ArgumentNullException();
            }

            if (grayImage2 == null)
            {
                throw new ArgumentNullException();
            }

            const int NotDividableMinAmountElements = 80;

            double[] pixelsData1 = grayImage1.PixelsData;
            double[] pixelsData2 = grayImage2.PixelsData;

            int pointsAmount = grayImage1.Width * grayImage1.Height;

            // Decide on how many partitions we should divade the processing
            // of the elements.
            var partsCount = pointsAmount > NotDividableMinAmountElements
                ? Environment.ProcessorCount
                : 1;

            var partSize = (int)(pointsAmount / partsCount);

            Parallel.For(0, partsCount, partIndex =>
            {
                var firstPointIndex = partIndex * partSize;
                var lastPointIndex  = firstPointIndex + partSize - 1;
                if (partIndex == partsCount - 1)
                {
                    lastPointIndex = pointsAmount - 1;
                }
                if (lastPointIndex > pointsAmount)
                {
                    lastPointIndex = pointsAmount - 1;
                }

                fixed(double *pixelsDataP1 = pixelsData1)
                fixed(double *pixelsDataP2 = pixelsData2)
                {
                    for (int pointIndex = lastPointIndex; pointIndex >= firstPointIndex; pointIndex--)
                    {
                        int i = pointIndex * 1;

                        // components should be in the range [0.0 , 1.0]
                        double g1 = *(pixelsDataP1 + i + 0);
                        double g2 = *(pixelsDataP2 + i + 0);

                        *(pixelsDataP1 + i + 0) = Math.Sqrt(g1 * g1 + g2 * g2);
                    }
                }
            });
        }
예제 #12
0
        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);
        }
예제 #13
0
        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));
        }
예제 #14
0
        public WhenRemoveComponents()
        {
            _pixelsData = new[]
            {
                0.00, 1.00, 2.00, 3.00, 0.50, 1.50, 2.50, 3.50,
                0.25, 1.25, 2.25, 3.25, 0.125, 1.125, 2.125, 3.125
            };

            _image = new ZsImage(_pixelsData, 2, 2, 4);
        }
예제 #15
0
        private Area2D GetImageAreaToProcess(ZsImage imageArgb, ZsImage markupArgb, byte levelsAmount)
        {
            var size = Calculate(imageArgb.Width, imageArgb.Height, levelsAmount);

            var markupArgbArea = markupArgb.FromArgbToArea2D();
            var offset         = CalculateOffset(size.Item1, size.Item2, markupArgbArea);

            var imageSrcArea = Area2D.Create((int)offset.X, (int)offset.Y, size.Item1, size.Item2);

            return(imageSrcArea);
        }
예제 #16
0
        public void Should_Throw_ArgumentOutOfRangeException_When_PatchSize_Less_Than_2(byte patchSize)
        {
            // Arrange
            var     detector = new PyramidLevelsDetector();
            ZsImage image    = CreateImage(100, 100);
            ZsImage markup   = CreateImage(50, 100);

            Action act = () => detector.CalculateLevelsAmount(image, markup, patchSize);

            // Act & Assert
            act.ShouldThrow <ArgumentOutOfRangeException>();
        }
예제 #17
0
        /// <summary>
        /// Runs the random NNF initialization iteration for the associated 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>
        /// <param name="areasMapping">The areas mapping. By default whole area of the dest image is associated with the whole area of the source image.</param>
        /// <exception cref="ArgumentNullException">destImage</exception>
        public void RunRandomNnfInitIteration(Nnf nnf, ZsImage destImage, ZsImage srcImage, PatchMatchSettings settings,
                                              ImagePatchDistanceCalculator patchDistanceCalculator, Area2DMap areasMapping)
        {
            if (destImage == null)
            {
                throw new ArgumentNullException(nameof(destImage));
            }

            var destPixelsArea = Area2D.Create(0, 0, destImage.Width, destImage.Height);

            RunRandomNnfInitIteration(nnf, destImage, srcImage, settings, patchDistanceCalculator, areasMapping, destPixelsArea);
        }
예제 #18
0
        public static unsafe void NormalizeWeights(this ZsImage grayImage, double w1, double w2, Area2D imageArea)
        {
            if (grayImage == null)
            {
                throw new ArgumentNullException();
            }

            const int  NotDividableMinAmountElements = 80;
            const byte componentsAmount = 1;

            double[] pixelsData1 = grayImage.PixelsData;

            int pointsAmount  = imageArea.ElementsCount;
            var pointIndecies = new int[pointsAmount];

            imageArea.FillMappedPointsIndexes(pointIndecies, grayImage.Width);

            // Decide on how many partitions we should divade the processing
            // of the elements.
            var partsCount = pointsAmount > NotDividableMinAmountElements
                ? Environment.ProcessorCount
                : 1;

            var partSize = (int)(pointsAmount / partsCount);

            Parallel.For(0, partsCount, partIndex =>
            {
                var firstPointIndex = partIndex * partSize;
                var lastPointIndex  = firstPointIndex + partSize - 1;
                if (partIndex == partsCount - 1)
                {
                    lastPointIndex = pointsAmount - 1;
                }
                if (lastPointIndex > pointsAmount)
                {
                    lastPointIndex = pointsAmount - 1;
                }

                fixed(double *pixelsDataP1 = pixelsData1)
                {
                    for (int j = lastPointIndex; j >= firstPointIndex; j--)
                    {
                        int absIndex = pointIndecies[j] * componentsAmount;

                        // components should be in the range [0.0 , 1.0]
                        double g = *(pixelsDataP1 + absIndex + 0);
                        g        = g > 1.0 ? 1.0 : g < 0.0 ? 0.0 : g;

                        *(pixelsDataP1 + absIndex + 0) = (g + w1) / w2;
                    }
                }
            });
        }
예제 #19
0
        public WhenSetComponentsValues()
        {
            _pixelsData = new[]
            {
                1.00, 1.00, 1.00, 0.50, 0.50, 0.50,
                0.25, 0.25, 0.25, 0.125, 0.125, 0.125
            };

            _image = new ZsImage(_pixelsData, 2, 2, 3);

            _area = Area2D.Create(0, 0, 2, 2);
        }
예제 #20
0
        private Pyramid BuildPyramid(ZsImage imageArgb, ZsImage markupArgb, IEnumerable <ZsImage> donorsArgb, byte levelsAmount, byte patchSize)
        {
            _pyramidBuilder.Init(imageArgb, markupArgb);
            foreach (var donorArgb in donorsArgb)
            {
                _pyramidBuilder.AddDonorMarkup(donorArgb);
            }

            var pyramid = _pyramidBuilder.Build(levelsAmount, patchSize);

            return(pyramid);
        }
예제 #21
0
        private static unsafe void FillMinSequence(int[] minSequence, ZsImage energyMap, Area2D imageArea)
        {
            if (energyMap == null)
            {
                throw new ArgumentNullException();
            }

            if (!IsRectangle(imageArea))
            {
                throw new ArgumentException("imageArea that has not rectangular shape is not allowed");
            }

            if (energyMap.Height != imageArea.Bound.Height)
            {
                throw new ArgumentException("imageArea should occupay the whole height of the energyMap");
            }

            double[] pixelsData = energyMap.PixelsData;

            int  width      = energyMap.Width;
            int  height     = energyMap.Height;
            byte cmpsAmount = energyMap.NumberOfComponents;

            int x = FindMinEnergySequenceStart(energyMap, imageArea);

            minSequence[height - 1] = x;

            var isValudIndex = CreateIndexValidator(imageArea, width);

            fixed(double *pixelsDataP = pixelsData)
            {
                for (int y = height - 2; y >= 0; y--)
                {
                    int tlIndex = y * width + (x - 1);
                    int trIndex = y * width + (x + 1);

                    double tl = x > 1 && isValudIndex(tlIndex) ? *(pixelsDataP + tlIndex * cmpsAmount + 0) : double.MaxValue;
                    double tc = *(pixelsDataP + (y * width + (x + 0)) * cmpsAmount + 0);
                    double tr = x < (width - 1) && isValudIndex(trIndex) ? *(pixelsDataP + trIndex * cmpsAmount + 0) : double.MaxValue;

                    if (tl < tc && tl < tr)
                    {
                        x = x - 1;
                    }
                    else if (tr < tl && tr < tc)
                    {
                        x = x + 1;
                    }
                    minSequence[y] = x;
                }
            }
        }
예제 #22
0
        public void Should_Throw_ArgumentNullException_When_RemoveMarkup_IsNull()
        {
            // Arrange
            var     detector  = new PyramidLevelsDetector();
            ZsImage image     = CreateImage(100, 100);
            ZsImage markup    = null;
            byte    patchSize = 7;

            Action act = () => detector.CalculateLevelsAmount(image, markup, patchSize);

            // Act & Assert
            act.ShouldThrow <ArgumentNullException>();
        }
예제 #23
0
        public void Should_Throw_AreaRemovedException_When_Markup_Covers_Image(int iw, int ih, int mw, int mh)
        {
            // Arrange
            var     detector  = new PyramidLevelsDetector();
            ZsImage image     = CreateImage(iw, ih);
            ZsImage markup    = CreateImage(mw, mh);
            byte    patchSize = 7;

            Action act = () => detector.CalculateLevelsAmount(image, markup, patchSize);

            // Act & Assert
            act.ShouldThrow <AreaRemovedException>();
        }
예제 #24
0
        public void Should_Return_1_When_Markup_IsEmpty_Inside_Image_Area()
        {
            // Arrange
            var     detector  = new PyramidLevelsDetector();
            ZsImage image     = CreateImage(100, 100);
            ZsImage markup    = Create3pixBiggerMarkupNotEmptyOutsideOfTheImage(100, 100);
            byte    patchSize = 7;

            // Act
            var levelsAmount = detector.CalculateLevelsAmount(image, markup, patchSize);

            // Assert
            levelsAmount.ShouldBe((byte)1);
        }
예제 #25
0
        public void Should_Return_1_When_Markup_IsEmpty()
        {
            // Arrange
            var     detector  = new PyramidLevelsDetector();
            ZsImage image     = CreateImage(100, 100);
            ZsImage markup    = CreateImage(100, 100, 0.0);
            byte    patchSize = 7;

            // Act
            var levelsAmount = detector.CalculateLevelsAmount(image, markup, patchSize);

            // Assert
            levelsAmount.ShouldBe((byte)1);
        }
예제 #26
0
        public void Should_Throw_ArgumentOutOfRangeException_Index_Greater_Than_Components_Amount(double[] pixels, int width, int height, byte componentsAmount, double[] components, byte index, Type expectedType)
        {
            var image = new ZsImage(pixels, width, height, componentsAmount);

            var result = typeof(object);

            try
            {
                image.InsertComponents(components, index);
            }
            catch (Exception ex)
            {
                result = ex.GetType();
            }
            result.ShouldBe(expectedType);
        }
예제 #27
0
        private static unsafe int FindMinEnergySequenceStart(ZsImage energyMap, Area2D imageArea)
        {
            if (energyMap == null)
            {
                throw new ArgumentNullException();
            }

            if (!IsRectangle(imageArea))
            {
                throw new ArgumentException("imageArea that has not rectangular shape is not allowed");
            }

            if (energyMap.Height != imageArea.Bound.Height)
            {
                throw new ArgumentException("imageArea should occupay the whole height of the energyMap");
            }

            double[] pixelsData = energyMap.PixelsData;

            int  width      = energyMap.Width;
            byte cmpsAmount = energyMap.NumberOfComponents;

            int startX = imageArea.Bound.X;
            int endX   = imageArea.Bound.Width + startX;

            int    minEnergyIndex = startX;
            int    y = energyMap.Height - 1;
            double currentEnergy;
            double minEnergy = double.MaxValue;

            fixed(double *pixelsDataP = pixelsData)
            {
                for (int x = startX; x < endX; x++)
                {
                    currentEnergy = *(pixelsDataP + (y * width + x) * cmpsAmount + 0);
                    if (currentEnergy < minEnergy)
                    {
                        minEnergy      = currentEnergy;
                        minEnergyIndex = x;
                    }
                }
            }

            return(minEnergyIndex);
        }
예제 #28
0
        public void Should_Insert_Provided_Values(double[] pixels, int width, int height, byte componentsAmount, double[] components, byte index, double[] result, bool expected)
        {
            var image = new ZsImage(pixels, width, height, componentsAmount);

            image.InsertComponents(components, index);
            var pixels2 = image.PixelsData;

            var equal = result.Length == pixels2.Length;

            for (int i = 0; i < result.Length && equal; i++)
            {
                if (result[i] != pixels2[i])
                {
                    equal = false;
                }
            }

            equal.ShouldBe(expected);
        }
예제 #29
0
        public static async Task SaveImageLabToBlob(ZsImage imageLab, CloudBlobContainer container, string fileName)
        {
            var argbImage = imageLab
                            .Clone()
                            .FromLabToRgb()
                            .FromRgbToArgb(Area2D.Create(0, 0, imageLab.Width, imageLab.Height));

            using (var bitmap = argbImage.FromArgbToBitmap())
                using (var outputStream = new MemoryStream())
                {
                    // modify image
                    bitmap.Save(outputStream, ImageFormat.Png);

                    // save the result back
                    outputStream.Position = 0;
                    var resultImageBlob = container.GetBlockBlobReference(fileName);
                    await resultImageBlob.UploadFromStreamAsync(outputStream);
                }
        }
예제 #30
0
        /// <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);
        }