Beispiel #1
0
        public void Should_Throw_IndexOutOfRangeException_When_Index_Greater_Than_DestElementsCount()
        {
            var areas = new[] { new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 10, 10), Area2D.Create(0, 0, 10, 10)) };
            var map   = new Area2DMap(areas, _emptyArea);

            Should.Throw <IndexOutOfRangeException>(() => { var p = map[100]; });
        }
Beispiel #2
0
        public void Should_Throw_IndexOutOfRangeException_When_Index_Less_Than_Zero()
        {
            var areas = new[] { new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 10, 10), Area2D.Create(0, 0, 10, 10)) };
            var map   = new Area2DMap(areas, _emptyArea);

            Should.Throw <IndexOutOfRangeException>(() => { var p = map[-1]; });
        }
Beispiel #3
0
        public void Should_Return_Points_That_Contained_In_Dest_Area()
        {
            var srcArea = Area2D.Create(0, 0, 3, 3);

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, _emptyArea);

            for (var i = 0; i < areaMap.DestElementsCount; i++)
            {
                var point = areaMap[i];
                var found = false;

                for (var j = 0; j < areas.Length; j++)
                {
                    var dest = areas[j].Item1;

                    if (dest.GetPointIndex(point) > -1)
                    {
                        found = true;
                        break;
                    }
                }

                found.ShouldBeTrue();
            }
        }
Beispiel #4
0
        public void Should_Contain_Points_From_Dest_Areas()
        {
            var srcArea = Area2D.Create(0, 0, 3, 3);

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, _emptyArea);

            for (var j = 0; j < areas.Length; j++)
            {
                var dest = areas[j].Item1;

                foreach (var destPoint in dest.Points)
                {
                    var found = false;

                    for (var i = 0; i < areaMap.DestElementsCount; i++)
                    {
                        var point = areaMap[i];

                        if (destPoint.X == point.X && destPoint.Y == point.Y)
                        {
                            found = true;
                        }
                    }

                    found.ShouldBeTrue();
                }
            }
        }
Beispiel #5
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();
        }
        public void Should_Return_Related_Source_Area(int x, int y, byte option)
        {
            var srcArea1  = Area2D.Create(0, 0, 3, 3);
            var srcArea2  = Area2D.Create(3, 3, 3, 3);
            var srcArea3  = Area2D.Create(6, 6, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea1),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea2),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea3)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            var result = areaMap.GetPointSourceArea(new Point(x, y));

            if (option == 1)
            {
                result.IsSameAs(srcArea1).ShouldBeTrue();
            }
            else if (option == 2)
            {
                result.IsSameAs(srcArea2).ShouldBeTrue();
            }
            else if (option == 3)
            {
                result.IsSameAs(srcArea3).ShouldBeTrue();
            }
        }
Beispiel #7
0
        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();
        }
Beispiel #8
0
        public void Should_Not_Contain_Duplicated_Points_Even_When_Dest_Areas_Have_Common_Parts()
        {
            var srcArea   = Area2D.Create(0, 0, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            var result       = areaMap.DestPoints;
            var noDuplicates = areaMap.DestPoints.Distinct();

            result.SequenceEqual(noDuplicates).ShouldBeTrue();
        }
        public void Should_Return_Empty_Area_When_Dest_Not_Contain_Point()
        {
            var srcArea   = Area2D.Create(0, 0, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            var result = areaMap.GetPointSourceArea(new Point(-10, 0));

            result.IsEmpty.ShouldBeTrue();
        }
        public static async Task NnfInitIteration([ActivityTrigger] NnfInputData input)
        {
            var container = BlobHelper.OpenBlobContainer(input.Container);

            var imageBlob = container.GetBlockBlobReference(input.Image);
            var imageArgb = await BlobHelper.ConvertBlobToArgbImage(imageBlob);

            var image = imageArgb
                        .FromArgbToRgb(new[] { 0.0, 0.0, 0.0 })
                        .FromRgbToLab();

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

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

            var nnfState = BlobHelper.ReadFromBlob <NnfState>(input.NnfName, container);
            var nnf      = new Nnf(nnfState);

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

            if (input.ExcludeInpaintArea)
            {
                var inpaintAreaState = BlobHelper.ReadFromBlob <Area2DState>(input.InpaintAreaName, container);
                var inpaintArea      = Area2D.RestoreFrom(inpaintAreaState);
                pixelsArea = imageArea.Substract(inpaintArea);
            }

            var nnfBuilder = new PatchMatchNnfBuilder();

            nnfBuilder.RunRandomNnfInitIteration(nnf, image, image, nnfSettings, calculator, mapping, pixelsArea);

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

            BlobHelper.SaveJsonToBlob(nnfData, container, input.NnfName);

            foreach (var subNnfName in input.SplittedNnfNames)
            {
                BlobHelper.SaveJsonToBlob(nnfData, container, subNnfName);
            }
        }
Beispiel #11
0
        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);
        }
        public void Should_Return_Source_That_Relates_To_Last_Dest_When_Point_Belongs_To_Several_Dest_Areas()
        {
            var srcArea1  = Area2D.Create(0, 0, 3, 3);
            var srcArea2  = Area2D.Create(3, 3, 3, 3);
            var srcArea3  = Area2D.Create(6, 6, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea1),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea2),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea3)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            var result = areaMap.GetPointSourceArea(new Point(4, 4));

            result.IsSameAs(srcArea2).ShouldBeTrue();
        }
Beispiel #13
0
        public void Should_Contain_All_Points_From_Dest_Areas()
        {
            var srcArea   = Area2D.Create(0, 0, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            for (var i = 0; i < areas.Length; i++)
            {
                var dest = areas[i].Item1;
                foreach (var point in dest.Points)
                {
                    areaMap.DestPoints.Contains(point).ShouldBeTrue();
                }
            }
        }
Beispiel #14
0
        public void Points_Area_Ordered_From_Left_To_Right_From_Top_To_Bottom()
        {
            var srcArea   = Area2D.Create(0, 0, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            var prevIndex = int.MinValue;

            foreach (var point in areaMap.DestPoints)
            {
                var index = point.Y * 1000 + point.X;
                index.ShouldBeGreaterThan(prevIndex);

                prevIndex = index;
            }
        }
Beispiel #15
0
        public void Should_Return_Ordered_From_Left_To_Right_From_Top_To_Bottom()
        {
            var srcArea = Area2D.Create(0, 0, 3, 3);

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, _emptyArea);

            var prevIndex = int.MinValue;

            for (var i = 0; i < areaMap.DestElementsCount; i++)
            {
                var point = areaMap[i];
                var index = point.Y * 1000 + point.X;
                index.ShouldBeGreaterThan(prevIndex);

                prevIndex = index;
            }
        }
        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);
        }
Beispiel #17
0
        /// <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);
        }
Beispiel #18
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="scaledMap">The areas mapping. By default whole area of the dest image is associated with the whole area of the source image.</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
        /// or
        /// scaledMap</exception>
        public static unsafe Nnf CloneAndScale2XWithUpdate(this Nnf nnf, ZsImage scaledDestImage, ZsImage scaledSrcImage, ParallelOptions options, Area2DMap scaledMap, ImagePatchDistanceCalculator patchDistanceCalculator = null, Area2D destPixelsArea = 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)
            {
                throw new ArgumentNullException(nameof(scaledMap));
            }

            if (destPixelsArea == null)
            {
                destPixelsArea = Area2D.Create(0, 0, scaledDestImage.Width, scaledDestImage.Height);
            }

            if (patchDistanceCalculator == null)
            {
                patchDistanceCalculator = ImagePatchDistance.Cie76;
            }

            if (options == null)
            {
                options = new ParallelOptions();
            }

            var patchSize      = nnf.PatchSize;
            var patchLength    = patchSize * patchSize;
            var destImageWidth = scaledDestImage.Width;
            var srcImageWidth  = scaledSrcImage.Width;
            var sameSrcAndDest = scaledDestImage == scaledSrcImage;

            var pixelsArea = (scaledMap as IAreasMapping).DestArea;

            //var destPointIndexes = GetDestPointsIndexes(pixelsArea, destImageWidth, NeighboursCheckDirection.Forward);
            pixelsArea = pixelsArea.Intersect(destPixelsArea);
            var destAvailablePixelsIndexes = pixelsArea.GetPointsIndexes(destImageWidth);
            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;

                // Init the dest & source patch
                var destPatchPixelsIndexes = new int[patchLength];
                var srcPatchPixelsIndexes  = new int[patchLength];

                //var destPointsIndexesSet = new HashSet<int>(destPointIndexes);
                var destAvailablePixelsIndexesSet = new HashSet <int>(destAvailablePixelsIndexes);
                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;
                }

                fixed(double *destImagePixelsDataP   = scaledDestImage.PixelsData)
                fixed(double *sourceImagePixelsDataP = scaledSrcImage.PixelsData)
                fixed(int *srcPatchPixelsIndexesP    = srcPatchPixelsIndexes)
                fixed(int *destPatchPixelsIndexesP   = destPatchPixelsIndexes)
                {
                    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 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]);
                                Utils.PopulatePatchPixelsIndexes(srcPatchPixelsIndexesP, srcX + offs[i][0], srcY + offs[i][1], patchSize, nnf2xSourceWidth, mappedAreasInfo.SrcAreaPointsIndexesSet, out isPatchFit);
                                Utils.PopulatePatchPixelsIndexes(destPatchPixelsIndexesP, destX + offs[i][0], destY + offs[i][1], patchSize, destImageWidth, destAvailablePixelsIndexesSet, out isPatchFit);
                                nnf2xData[destPointIndex * 2 + 1] = patchDistanceCalculator.Calculate(destPatchPixelsIndexesP, srcPatchPixelsIndexesP, double.MaxValue, destImagePixelsDataP, sourceImagePixelsDataP, scaledDestImage, scaledSrcImage, patchLength);
                            }
                            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);
        }
        public static Tuple <int, Area2DMap>[] GetMapAndCount()
        {
            var data = new List <Tuple <int, Area2DMap> >();

            var srcArea   = Area2D.Create(0, 0, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            data.Add(new Tuple <int, Area2DMap>(87, areaMap));

            areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
            };
            areaMap = new Area2DMap(areas, emptyArea);
            data.Add(new Tuple <int, Area2DMap>(25, areaMap));

            areas = new[]
            {
                new Tuple <Area2D, Area2D>(
                    Area2D.Create(-5, 0, new []
                {
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
                }),
                    srcArea),
            };
            areaMap = new Area2DMap(areas, emptyArea);
            data.Add(new Tuple <int, Area2DMap>(4, areaMap));

            areas = new[]
            {
                new Tuple <Area2D, Area2D>(
                    Area2D.Create(-5, 0, new []
                {
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
                }),
                    srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 20, 20), srcArea),
            };
            areaMap = new Area2DMap(areas, emptyArea);
            data.Add(new Tuple <int, Area2DMap>(402, areaMap));

            return(data.ToArray());
        }
        public static Tuple <Rectangle, Area2DMap>[] GetMapAndRect()
        {
            List <Tuple <Rectangle, Area2DMap> > data = new List <Tuple <Rectangle, Area2DMap> >();

            var srcArea   = Area2D.Create(0, 0, 3, 3);
            var emptyArea = Area2D.Empty;

            var areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 6, 6), srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(-3, -3, 6, 6), srcArea)
            };
            var areaMap = new Area2DMap(areas, emptyArea);

            data.Add(new Tuple <Rectangle, Area2DMap>(new Rectangle(-3, -3, 13, 13), areaMap));


            areas = new[]
            {
                new Tuple <Area2D, Area2D>(Area2D.Create(0, 0, 5, 5), srcArea),
            };
            areaMap = new Area2DMap(areas, emptyArea);
            data.Add(new Tuple <Rectangle, Area2DMap>(new Rectangle(0, 0, 5, 5), areaMap));

            areas = new[]
            {
                new Tuple <Area2D, Area2D>(
                    Area2D.Create(-5, 0, new []
                {
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
                }),
                    srcArea),
            };
            areaMap = new Area2DMap(areas, emptyArea);
            data.Add(new Tuple <Rectangle, Area2DMap>(new Rectangle(-5, 0, 16, 16), areaMap));

            areas = new[]
            {
                new Tuple <Area2D, Area2D>(
                    Area2D.Create(-5, 0, new []
                {
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
                }),
                    srcArea),
                new Tuple <Area2D, Area2D>(Area2D.Create(4, 4, 20, 20), srcArea),
            };
            areaMap = new Area2DMap(areas, emptyArea);
            data.Add(new Tuple <Rectangle, Area2DMap>(new Rectangle(-5, 0, 29, 24), areaMap));

            return(data.ToArray());
        }
Beispiel #21
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>
        /// <param name="destPixelsArea">Area on the dest image that actually containes pixels. By default is the area of the entire image.</param>
        /// <exception cref="ArgumentNullException">
        /// nnf
        /// or
        /// destImage
        /// or
        /// srcImage
        /// or
        /// settings
        /// or
        /// patchDistanceCalculator
        /// or
        /// areasMapping
        /// or
        /// destPixelsArea
        /// </exception>
        public unsafe void RunRandomNnfInitIteration(Nnf nnf, ZsImage destImage, ZsImage srcImage, PatchMatchSettings settings, ImagePatchDistanceCalculator patchDistanceCalculator, Area2DMap areasMapping, Area2D destPixelsArea)
        {
            if (nnf == null)
            {
                throw new ArgumentNullException(nameof(nnf));
            }
            if (destImage == null)
            {
                throw new ArgumentNullException(nameof(destImage));
            }
            if (srcImage == null)
            {
                throw new ArgumentNullException(nameof(srcImage));
            }
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }
            if (patchDistanceCalculator == null)
            {
                throw new ArgumentNullException(nameof(patchDistanceCalculator));
            }
            if (areasMapping == null)
            {
                throw new ArgumentNullException(nameof(areasMapping));
            }
            if (destPixelsArea == null)
            {
                throw new ArgumentNullException(nameof(destPixelsArea));
            }

            const byte MaxAttempts = 32;

            var nnfdata           = nnf.GetNnfItems();
            var patchSize         = settings.PatchSize;
            var patchPointsAmount = patchSize * patchSize;
            var destImageWidth    = destImage.Width;
            var srcImageWidth     = srcImage.Width;

            // Decide on how many partitions we should divade the processing
            // of the elements.
            var partsCount = areasMapping.DestElementsCount > settings.NotDividableMinAmountElements
                ? settings.ThreadsCount
                : 1;
            var partSize = (int)(areasMapping.DestElementsCount / partsCount);

            var pixelsArea        = (areasMapping as IAreasMapping).DestArea;
            var destPointsIndexes = pixelsArea.GetPointsIndexes(destImageWidth);

            pixelsArea = pixelsArea.Intersect(destPixelsArea);
            var destAvailablePixelsIndexes = pixelsArea.GetPointsIndexes(destImageWidth);
            var mappings = areasMapping.ExtractMappedAreasInfo(destImageWidth, srcImageWidth);

            //for (int partIndex = 0; partIndex < partsCount; partIndex++)
            Parallel.For(0, partsCount, partIndex =>
            {
                // Colne mapping to avoid conflicts in multithread
                //var destPointsIndexesSet = new HashSet<int>(destPointsIndexes);
                var destAvailablePixelsIndexesSet = new HashSet <int>(destAvailablePixelsIndexes);

                var mappedAreasInfos = new MappedAreasInfo[mappings.Length];
                for (int i = 0; i < mappings.Length; i++)
                {
                    mappedAreasInfos[i] = mappings[i].Clone();
                }

                #region Variables definition
                int destPointIndex;
                int destPointX;
                int destPointY;

                int srcPointIndex = 0;
                int srcPointX;
                int srcPointY;

                double distance;
                int nnfPos;
                byte attemptsCount = 0;
                #endregion

                var rnd = new FastRandom();

                var firstPointIndex = partIndex * partSize;
                var lastPointIndex  = firstPointIndex + partSize - 1;
                if (partIndex == partsCount - 1)
                {
                    lastPointIndex = areasMapping.DestElementsCount - 1;
                }
                if (lastPointIndex > areasMapping.DestElementsCount)
                {
                    lastPointIndex = areasMapping.DestElementsCount - 1;
                }

                // Init the dest & source patch
                var destPatchPointIndexes = new int[patchPointsAmount];
                var srcPatchPointIndexes  = new int[patchPointsAmount];
                bool isPatchFit           = false;

                fixed(double *nnfdataP            = nnfdata)
                fixed(int *dstPointIndexesP       = destPointsIndexes)
                fixed(int *srcPatchPointIndexesP  = srcPatchPointIndexes)
                fixed(int *destPatchPointIndexesP = destPatchPointIndexes)
                fixed(double *destPixelsDataP     = destImage.PixelsData)
                fixed(double *sourcePixelsDataP   = srcImage.PixelsData)
                {
                    for (var pointIndex = firstPointIndex; pointIndex <= lastPointIndex; pointIndex++)
                    {
                        destPointIndex = *(dstPointIndexesP + pointIndex);
                        destPointX     = destPointIndex % destImageWidth;
                        destPointY     = destPointIndex / destImageWidth;

                        Utils.PopulatePatchPixelsIndexes(destPatchPointIndexesP, destPointX, destPointY, patchSize, destImageWidth, destAvailablePixelsIndexesSet, out isPatchFit);

                        nnfPos = destPointIndex * 2;

                        // Obtain the source area associated with the destination area
                        // to which the current dest point belongs to.
                        // In that area we are allowed to look for the source patches.
                        MappedAreasInfo mappedAreasInfo = mappedAreasInfos.FirstOrDefault(mai => mai.DestAreaPointsIndexesSet.Contains(destPointIndex));

                        isPatchFit          = false;
                        attemptsCount       = 0;
                        var srcPointsAmount = mappedAreasInfo.SrcAreaPointsIndexes.Length;
                        while (!isPatchFit && attemptsCount < MaxAttempts && attemptsCount < srcPointsAmount)
                        {
                            srcPointIndex = mappedAreasInfo.SrcAreaPointsIndexes[rnd.Next(srcPointsAmount)];
                            srcPointX     = srcPointIndex % srcImageWidth;
                            srcPointY     = srcPointIndex / srcImageWidth;

                            Utils.PopulatePatchPixelsIndexes(srcPatchPointIndexesP, srcPointX, srcPointY, patchSize, srcImageWidth, mappedAreasInfo.SrcAreaPointsIndexesSet, out isPatchFit);
                            attemptsCount++;
                        }

                        distance = patchDistanceCalculator.Calculate(destPatchPointIndexesP, srcPatchPointIndexesP, double.MaxValue,
                                                                     destPixelsDataP, sourcePixelsDataP, destImage, srcImage, patchPointsAmount);

                        *(nnfdataP + nnfPos + 0) = srcPointIndex;
                        *(nnfdataP + nnfPos + 1) = distance;
                    }
                }
            });
        }
Beispiel #22
0
        /// <summary>
        /// Merges provided NNF into.
        /// </summary>
        /// <param name="destNnf">The dest NNF.</param>
        /// <param name="srcNnf">The source NNF.</param>
        /// <param name="destNnfMap">The dest NNF areas mapping.</param>
        /// <param name="srcNnfMap">The source NNF areas mapping.</param>
        /// <param name="options">The parallel processing options.</param>
        /// <exception cref="ArgumentNullException">
        /// destNnf
        /// or
        /// srcNnf
        /// or
        /// destNnfMap
        /// or
        /// srcNnfMap
        /// </exception>
        /// <exception cref="ArgumentException">NNFs should be built for the same source and dest images</exception>
        public static unsafe void Merge(this Nnf destNnf, Nnf srcNnf, Area2DMap destNnfMap, Area2DMap srcNnfMap, ParallelOptions options = null)
        {
            if (destNnf == null)
            {
                throw new ArgumentNullException(nameof(destNnf));
            }
            if (srcNnf == null)
            {
                throw new ArgumentNullException(nameof(srcNnf));
            }
            if (destNnfMap == null)
            {
                throw new ArgumentNullException(nameof(destNnfMap));
            }
            if (srcNnfMap == null)
            {
                throw new ArgumentNullException(nameof(srcNnfMap));
            }

            // We assume that all the inputs contain NNFs
            // for the same dest image.
            // The source images can not be different as well.
            // When different source images are desired those
            // images should be merged to one image and mappings
            // should be adjusted to map to a particular region
            // on the source image.
            // Differen source images problem. In that case we
            // have a problem with different mappings when we
            // merge NNfs. Mappings can not be merged as they
            // would have totally different source areas.

            // make sure that both NNFs are built for the same dest and source images
            if (destNnf.DstWidth != srcNnf.DstWidth || destNnf.DstHeight != srcNnf.DstHeight ||
                destNnf.SourceWidth != srcNnf.SourceWidth || destNnf.SourceHeight != srcNnf.SourceHeight)
            {
                throw new ArgumentException("NNFs should be built for the same source and dest images");
            }

            if (options == null)
            {
                options = new ParallelOptions();
            }

            var destImageWidth = destNnf.DstWidth;
            var srcImageWidth  = destNnf.SourceWidth;

            // Nnf that needs to be merged to our dest nnf.
            var srcNnfData  = srcNnf.GetNnfItems();
            var destNnfData = destNnf.GetNnfItems();

            var destNnfPointsIndexes = (destNnfMap as IAreasMapping).DestArea.GetPointsIndexes(destImageWidth);
            var srcNnfPointsIndexes  = (srcNnfMap as IAreasMapping).DestArea.GetPointsIndexes(destImageWidth);
            var mappings             = srcNnfMap.ExtractMappedAreasInfo(destImageWidth, srcImageWidth);

            // Decide on how many partitions we should divade the processing
            // of the elements.
            int partsCount = srcNnfMap.DestElementsCount > options.NotDividableMinAmountElements
                ? options.ThreadsCount
                : 1;
            var partSize = (int)(srcNnfMap.DestElementsCount / partsCount);

            Parallel.For(0, partsCount, partIndex =>
            {
                // Colne mapping to avoid conflicts in multithread
                var destNnfPointsIndexesSet = new HashSet <int>(destNnfPointsIndexes);

                // Clone mappings to avoid problems in multithread
                var mappedAreasInfos = new MappedAreasInfo[mappings.Length];
                for (int j = 0; j < mappings.Length; j++)
                {
                    mappedAreasInfos[j] = mappings[j].Clone();
                }

                var firstPointIndex = partIndex * partSize;
                var lastPointIndex  = firstPointIndex + partSize - 1;
                if (partIndex == partsCount - 1)
                {
                    lastPointIndex = srcNnfMap.DestElementsCount - 1;
                }
                if (lastPointIndex > srcNnfMap.DestElementsCount)
                {
                    lastPointIndex = srcNnfMap.DestElementsCount - 1;
                }

                fixed(double *destNnfP         = destNnfData)
                fixed(double *srcNnfP          = srcNnfData)
                fixed(int *srcNnfPointIndexesP = srcNnfPointsIndexes)
                {
                    for (var srcNnfMapDestPointIndex = firstPointIndex; srcNnfMapDestPointIndex <= lastPointIndex; srcNnfMapDestPointIndex++)
                    {
                        var destPointIndex = *(srcNnfPointIndexesP + srcNnfMapDestPointIndex);

                        if (destNnfPointsIndexesSet.Contains(destPointIndex))
                        {
                            // The value of the NNF in the dest point can
                            // present in the resulting destNnf as well.
                            // In that case we need to merge NNFs at the point
                            // by taking the best value.

                            // compare and set the best
                            var srcVal  = *(srcNnfP + destPointIndex * 2 + 1);
                            var destVal = *(destNnfP + destPointIndex * 2 + 1);

                            if (srcVal < destVal)
                            {
                                *(destNnfP + destPointIndex * 2 + 0) = *(srcNnfP + destPointIndex * 2 + 0);
                                *(destNnfP + destPointIndex * 2 + 1) = srcVal;
                            }
                        }
                        else
                        {
                            // When the destNnf doesn't contain the value
                            // for that point we simply copy it
                            *(destNnfP + destPointIndex * 2 + 0) = *(srcNnfP + destPointIndex * 2 + 0);
                            *(destNnfP + destPointIndex * 2 + 1) = *(srcNnfP + destPointIndex * 2 + 1);
                        }
                    }
                }
            });
        }
Beispiel #23
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);
        }
Beispiel #24
0
        /// <summary>
        /// Runs the NNF build 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="direction">The direction to look for a patches.</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>
        /// <param name="destPixelsArea">Area on the dest image that actually containes pixels. By default is the area of the entire image.</param>
        /// <exception cref="ArgumentNullException">
        /// nnf
        /// or
        /// destImage
        /// or
        /// srcImage
        /// or
        /// settings
        /// or
        /// patchDistanceCalculator
        /// or
        /// areasMapping
        /// or
        /// destPixelsArea
        /// </exception>
        public unsafe void RunBuildNnfIteration(Nnf nnf, ZsImage destImage, ZsImage srcImage, NeighboursCheckDirection direction, PatchMatchSettings settings, ImagePatchDistanceCalculator patchDistanceCalculator, Area2DMap areasMapping, Area2D destPixelsArea)
        {
            if (nnf == null)
            {
                throw new ArgumentNullException(nameof(nnf));
            }
            if (destImage == null)
            {
                throw new ArgumentNullException(nameof(destImage));
            }
            if (srcImage == null)
            {
                throw new ArgumentNullException(nameof(srcImage));
            }
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }
            if (patchDistanceCalculator == null)
            {
                throw new ArgumentNullException(nameof(patchDistanceCalculator));
            }
            if (areasMapping == null)
            {
                throw new ArgumentNullException(nameof(areasMapping));
            }
            if (destPixelsArea == null)
            {
                throw new ArgumentNullException(nameof(destPixelsArea));
            }

            sbyte offs = (sbyte)(direction == NeighboursCheckDirection.Forward ? 1 : -1);

            sbyte[][] offsets =
            {
                new[] { offs,     (sbyte)0 },
                new[] { (sbyte)0, offs     }
            };

            #region Cache settings and inputs in the local variables
            var nnfdata     = nnf.GetNnfItems();
            var nnfSrcWidth = nnf.SourceWidth;

            var patchSize          = settings.PatchSize;
            var patchLength        = patchSize * patchSize;
            var randomSearchRadius = settings.RandomSearchRadius;
            var alpha = settings.RandomSearchAlpha;
            var minSearchWindowSize = settings.MinSearchWindowSize;

            var destImageWidth = destImage.Width;
            var srcImageWidth  = srcImage.Width;
            #endregion

            // Obtain the data that allow us getting a point index
            // regarding to the process direction(forward or backward)
            var addModData = GetAddModData(direction, areasMapping.DestElementsCount);
            var add        = addModData.Item1;
            var mod        = addModData.Item2;

            // Decide on how many partitions we should divade the processing
            // of the elements.
            var partsCount = areasMapping.DestElementsCount > settings.NotDividableMinAmountElements
                ? settings.ThreadsCount
                : 1;
            var partSize = areasMapping.DestElementsCount / partsCount;

            var pixelsArea       = (areasMapping as IAreasMapping).DestArea;
            var destPointIndexes = pixelsArea.GetPointsIndexes(destImageWidth, direction == NeighboursCheckDirection.Forward);
            pixelsArea = pixelsArea.Intersect(destPixelsArea);
            var destAvailablePixelsIndexes = pixelsArea.GetPointsIndexes(destImageWidth, direction == NeighboursCheckDirection.Forward);

            var mappings = areasMapping.ExtractMappedAreasInfo(destImageWidth, srcImageWidth, direction == NeighboursCheckDirection.Forward);

            //for (int partIndex = 0; partIndex < partsCount; partIndex++)
            Parallel.For(0, partsCount, partIndex =>
            {
                var rnd = new FastRandom();
                int i;

                // Colne mapping to avoid conflicts in multithread
                //var destPointsIndexesSet = new HashSet<int>(destPointIndexes);
                var destAvailablePixelsIndexesSet = new HashSet <int>(destAvailablePixelsIndexes);
                var mappedAreasInfos = new MappedAreasInfo[mappings.Length];
                for (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 = destPointIndexes.Length - 1;
                }
                if (lastPointIndex > destPointIndexes.Length)
                {
                    lastPointIndex = destPointIndexes.Length - 1;
                }

                // Init the dest & source patch
                var destPatchPixelsIndexes = new int[patchSize * patchSize];
                var srcPatchPixelsIndexes  = new int[patchSize * patchSize];

                bool isPatchFit = false;

                fixed(double *nnfP                   = nnfdata)
                fixed(int *destPointIndexesP         = destPointIndexes)
                fixed(int *srcPatchPixelsIndexesP    = srcPatchPixelsIndexes)
                fixed(int *destPatchPixelsIndexesP   = destPatchPixelsIndexes)
                fixed(double *destImagePixelsDataP   = destImage.PixelsData)
                fixed(double *sourceImagePixelsDataP = srcImage.PixelsData)
                {
                    for (var j = firstPointIndex; j <= lastPointIndex; j++)
                    {
                        // Obtain a destination point from the mapping.
                        // The dest point is the position of the dest patch.
                        // Chocie of the destination point depends on the
                        // direction in which we iterate the points (forward or backward).
                        var destPointIndex = *(destPointIndexesP + add + j * mod);
                        var destPointX     = destPointIndex % destImageWidth;
                        var destPointY     = destPointIndex / destImageWidth;

                        // We going to find the most similar source patch to the dest patch
                        // by comparing them.
                        // Note: we don't care about the coverage state of the dest patch
                        // because it is at least partially covered. The situation when it is
                        // not covered at all is impossible, since the dest point is a part of the
                        // dest area.

                        // We store our patch in a flat array of points for simplicity.
                        // Populate dest patch array with corresponding dest image points indexes.
                        Utils.PopulatePatchPixelsIndexes(destPatchPixelsIndexesP, destPointX, destPointY, patchSize, destImageWidth, destAvailablePixelsIndexesSet, out isPatchFit);

                        // Obtain the mapped areas info with the destination area
                        // that contains the current dest point. In the associated
                        // source area we are allowed to look for the source patches.
                        MappedAreasInfo mappedAreasInfo = mappedAreasInfos.FirstOrDefault(mai => mai.DestAreaPointsIndexesSet.Contains(destPointIndex));

                        // To improve performance, we cache the value of the NNF
                        // at the current point in the local variables.
                        var nnfPos                 = destPointIndex * 2;
                        var bestSrcPointIndex      = (int)*(nnfP + nnfPos + 0);
                        var distanceToBestSrcPatch = *(nnfP + nnfPos + 1);

                        // We assume that the value of the NNF at the current
                        // point is the best so far and we have not found anything beter.
                        var isBetterSrcPatchFound = false;

                        // Now we check two close neighbours. First - horisontal, than vertical.

                        #region f(x - p) + (1, 0) & f(x - p) + (0, 1)

                        //1st iteration: f(x - p) + (1, 0)
                        //2nd iteration: f(x - p) + (0, 1)

                        int candidateSrcPointY = 0;
                        int candidateSrcPointX = 0;
                        double distance;
                        for (var offsetIndex = 0; offsetIndex < offsets.Length; offsetIndex++)
                        {
                            // Obtain the position of the neighbour.
                            // During the forward search
                            //  on the first iteration it is the neighbour at the left side
                            //  on the second iteration it is the neighbour at the top
                            // During the backward search
                            //  on the first iteration it is the neighbour at the right side
                            //  on the second iteration it is the neighbour at the bottom

                            var offset = offsets[offsetIndex];
                            var destPointNeighbourX     = destPointX - offset[0];
                            var destPointNeighbourY     = destPointY - offset[1];
                            var destPointNeighbourIndex = destPointNeighbourY * destImageWidth + destPointNeighbourX;

                            // Make sure that the neighbour point belongs to the mapping
                            if (!mappedAreasInfo.DestAreaPointsIndexesSet.Contains(destPointNeighbourIndex))
                            {
                                continue;
                            }

                            // There is a high chance that the neighbour's source patch neighbour
                            // is similar to the current dest patch. Let's check it.
                            // Obtain the position of the neighbour's source patch neighbour.
                            var neighbourNnfPos        = 2 * destPointNeighbourIndex;
                            var neighbourSrcPointIndex = (int)*(nnfP + neighbourNnfPos + 0);
                            candidateSrcPointY         = neighbourSrcPointIndex / nnfSrcWidth + offset[1];
                            candidateSrcPointX         = neighbourSrcPointIndex % nnfSrcWidth + offset[0];
                            var candidateSrcPointIndex = candidateSrcPointY * srcImageWidth + candidateSrcPointX;

                            // Make sure that the source patch resides inside the
                            // associated source area of the dest area.
                            if (!mappedAreasInfo.SrcAreaPointsIndexesSet.Contains(candidateSrcPointIndex))
                            {
                                continue;
                            }

                            // Populate source patch array with corresponding source image points indexes
                            Utils.PopulatePatchPixelsIndexes(srcPatchPixelsIndexesP, candidateSrcPointX, candidateSrcPointY, patchSize, srcImageWidth, mappedAreasInfo.SrcAreaPointsIndexesSet, out isPatchFit);

                            // Calculate distance between the patches
                            distance = patchDistanceCalculator.Calculate(destPatchPixelsIndexesP, srcPatchPixelsIndexesP, distanceToBestSrcPatch, destImagePixelsDataP, sourceImagePixelsDataP, destImage, srcImage, patchLength);

                            if (isPatchFit && distance < distanceToBestSrcPatch)
                            {
                                isBetterSrcPatchFound  = true;
                                bestSrcPointIndex      = candidateSrcPointIndex;
                                distanceToBestSrcPatch = distance;
                            }
                        }

                        #endregion

                        #region random search

                        //v0 = f(x)

                        // For the random search we need to find out
                        // the size of the window where to search
                        var srcAreaBound     = mappedAreasInfo.SrcBound;
                        var srcAreaWidth     = srcAreaBound.Width;
                        var srcAreaHeight    = srcAreaBound.Height;
                        var searchWindowSize = srcAreaHeight < srcAreaWidth ? srcAreaHeight : srcAreaWidth;
                        if (searchWindowSize > minSearchWindowSize)
                        {
                            searchWindowSize = minSearchWindowSize;
                        }

                        // Init the search radius;
                        var searchRadius  = randomSearchRadius;
                        var bestSrcPointX = bestSrcPointIndex % srcImageWidth;
                        var bestSrcPointY = bestSrcPointIndex / srcImageWidth;

                        for (i = 0; searchRadius >= 1; i++)
                        {
                            //TODO: change and measure inpact of changing call to Pow
                            searchRadius = searchWindowSize * System.Math.Pow(alpha, i);

                            isPatchFit   = false;
                            var attempts = 0;

                            while (!isPatchFit && attempts < 5)
                            {
                                attempts++;
                                candidateSrcPointX = (int)(bestSrcPointX + (rnd.NextDouble() * 2 - 1.0) * searchRadius);
                                candidateSrcPointY = (int)(bestSrcPointY + (rnd.NextDouble() * 2 - 1.0) * searchRadius);

                                // Populate source patch array with corresponding source image points indexes
                                Utils.PopulatePatchPixelsIndexes(srcPatchPixelsIndexesP, candidateSrcPointX, candidateSrcPointY, patchSize, srcImageWidth, mappedAreasInfo.SrcAreaPointsIndexesSet, out isPatchFit);
                            }

                            // Calculate distance between the patches
                            distance = patchDistanceCalculator.Calculate(destPatchPixelsIndexesP, srcPatchPixelsIndexesP, distanceToBestSrcPatch, destImagePixelsDataP, sourceImagePixelsDataP, destImage, srcImage, patchLength);

                            if (isPatchFit && distance < distanceToBestSrcPatch)
                            {
                                distanceToBestSrcPatch = distance;
                                bestSrcPointIndex      = candidateSrcPointY * srcImageWidth + candidateSrcPointX;
                                isBetterSrcPatchFound  = true;
                            }
                        }

                        #endregion

                        if (isBetterSrcPatchFound)
                        {
                            *(nnfP + nnfPos + 0) = bestSrcPointIndex;
                            *(nnfP + nnfPos + 1) = distanceToBestSrcPatch;
                        }
                    }
                }
            });
        }
Beispiel #25
0
        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;
        }
Beispiel #26
0
 public PmData(ZsImage destImage, ZsImage srcImage, Area2DMap map)
     : this(destImage, srcImage, new Nnf(destImage.Width, destImage.Height, srcImage.Width, srcImage.Height), map)
 {
 }