public Rectangle MinDistanceRegion(Rectangle sourceRect, ImgGradient gradient, Pixel[,] layerPixels, SelectionMask selectionMask)
        {
            Debug.Assert(sourceRect.Width == sourceRect.Height);

            var windowSize = sourceRect.Width;
            var windowDelta = windowSize/2;
            var layerWidth = layerPixels.GetLength(0);
            var layerHeight = layerPixels.GetLength(1);

            Rectangle minRegionRect = null;
            var minDistance = 0.0;
            var adjustedSourceRect = sourceRect.AdjustedToImageEdges(new Rectangle(new IntCoordinate(0, 0),
                                                                                   layerWidth, layerHeight));
            var currentCoordinate = new IntCoordinate(0, 0);
            var orthoGradient = new Coordinate<double>(-gradient.YMagnitude*windowDelta,
                                                       gradient.XMagnitude*windowDelta);
            for (int i = windowDelta; i < layerWidth - windowDelta; i++)
            {
                for (int j = windowDelta; j < layerHeight - windowDelta; j++)
                {
                    if (j == sourceRect.Y1 + windowDelta && i == sourceRect.X1 + windowDelta)
                    {
                        continue;
                    }
                    currentCoordinate.X = i;
                    currentCoordinate.Y = j;
                    var currentRgnRect = currentCoordinate.PointCenteredRectangle(windowSize);
                    var dist = RegionDistance(adjustedSourceRect, currentRgnRect, layerPixels, selectionMask);
                    if (dist == null)
                    {
                        continue;
                    }
                    if (dist == 0)
                    {
                        return currentRgnRect;
                    }
                    if ((minDistance > dist || minRegionRect == null))
                    {
                        minDistance = (double) dist;
                        minRegionRect = currentRgnRect;
                    }
                }
            }

            return minRegionRect;
        }
        public Rectangle MinDistanceRegion(Rectangle sourceRect, Drawable drawable, SelectionMask selectionMask)
        {
            Debug.Assert(sourceRect.Width == sourceRect.Height);

            var windowSize = sourceRect.Width;
            var windowDelta = windowSize/2;
            Rectangle minRegionRect = null;

            var minDistance = 0.0;

            var sourceRgn = new PixelRgn(drawable, sourceRect.AdjustedToImageEdges(drawable.Bounds), false, false);
            var sourceArray = sourceRgn.ToArrayWithoutSelection(selectionMask);

            var currentCoordinate = new IntCoordinate(0, 0);
            for (int i = windowDelta; i < drawable.Width - windowDelta; i++)
            {
                for (int j = windowDelta; j < drawable.Height - windowDelta; j++)
                {
                    if (j == sourceRect.Y1 + windowDelta && i == sourceRect.X1 + windowDelta)
                    {
                        continue;
                    }
                    currentCoordinate.X = i;
                    currentCoordinate.Y = j;
                    var currentRgnRect = currentCoordinate.PointCenteredRectangle(windowSize);
                    var dist = RegionDistance(sourceArray, currentRgnRect, drawable, selectionMask);
                    if (dist == null)
                    {
                        continue;
                    }
                    if (dist == 0)
                    {
                        return currentRgnRect;
                    }
                    if ((minDistance > dist || minRegionRect == null))
                    {
                        minDistance = (double) dist;
                        minRegionRect = currentRgnRect;
                    }
                }
            }

            return minRegionRect;
        }
        public double? RegionDistance(Pixel[,] source, Rectangle rgnRect, Drawable drawable, SelectionMask selectionMask)
        {
            var sum = 0.0;
            var sourceWidth = source.GetLength(0);
            var sourceHeight = source.GetLength(1);
            var rgn = new PixelRgn(drawable, rgnRect, false, false);
            for (IntPtr pr = PixelRgn.Register(rgn);
                 pr != IntPtr.Zero;
                 pr = PixelRgn.Process(pr))
            {
                for (int y1 = rgn.Y - rgnRect.UpperLeft.Y, y2 = rgn.Y;
                     y2 < rgn.Y + rgn.H;
                     y1++, y2++)
                {
                    for (int x1 = rgn.X - rgnRect.UpperLeft.X, x2 = rgn.X;
                         x2 < rgn.X + rgn.W;
                         x1++, x2++)
                    {
                        if (selectionMask[x2, y2])
                        {
                            return null;
                        }
                        if (x1 >= sourceWidth ||
                            x2 >= sourceHeight ||
                            source[x1, y1] == null)
                        {
                            continue;
                        }

                        sum += DistanceSqr(source[x1, y1], rgn[y2, x2]);
                    }
                }
            }

            return sum;
        }
        public double? RegionDistance(Rectangle sourceRect, Rectangle rgnRect, Pixel[,] layerPixels,
                                      SelectionMask selectionMask)
        {
            var sum = 0.0;
            var sourceWidth = sourceRect.Width;
            var sourceHeight = sourceRect.Height;

            for (int y1 = sourceRect.Y1, y2 = rgnRect.Y1;
                 y1 < sourceRect.Y1 + sourceHeight;
                 y1++, y2++)
            {
                for (int x1 = sourceRect.X1, x2 = rgnRect.X1;
                     x1 < sourceRect.X1 + sourceWidth;
                     x1++, x2++)
                {
                    //if there's selection pixel inside of examined region mark region as useless
                    if (selectionMask[x2, y2])
                    {
                        return null;
                    }
                    //if it's pixel from target region don't examine it
                    if (selectionMask[x1, y1])
                    {
                        continue;
                    }

                    sum += DistanceSqr(layerPixels[x1, y1], layerPixels[x2, y2]);
                }
            }

            return sum;
        }
예제 #5
0
        public void Render(Image image, Drawable drawable)
        {
            if (image.Selection.Empty)
            {
                return;
            }
            image.UndoGroupStart();
            Tile.CacheDefault(drawable);

            var temp = image.Duplicate();
            var imageRect = image.Bounds;

            var layerPixels = LayerToArray(imageRect, drawable);

            //temp.Selection.Border(1);
            bool selectionNonEmpty;
            var selectionBounds = temp.Selection.Bounds(out selectionNonEmpty);
            var selectionMask = new SelectionMask(temp.Selection);

            //var progress = new Progress(_("Filling the region..."));
            var initArea = selectionMask.Area;

            //init confidance term
            //TODO throw out rgniterator from here
            var pxConfidenceTerm = RegionHelper.FilledMatrix(image.Width, image.Height, 1.0);
            var iter = new RgnIterator(image.Selection, RunMode.Noninteractive);
            iter.IterateSrc(pixel => pxConfidenceTerm[pixel.X, pixel.Y] = selectionMask[pixel.X, pixel.Y] ? 0 : 1);

            int iteration = 0;
            while (!selectionMask.Empty && iteration < _iterations)
            {
                //  initial selection border / target region
                var selectionBorder =
                    RegionHelper.TraceBorder(selectionBounds,
                                             coord => selectionMask[coord.X, coord.Y])
                                .ToList();

                var borderConfidanceValues = NewConfidanceValue(selectionBorder, pxConfidenceTerm, _windowSize);
                var borderGradientValues = GradientValues(selectionBorder, layerPixels, selectionMask, _windowSize).ToList();
                var borderNormals = NormalVectors.CalculateNormals(selectionBorder);
                var borderDataTerms = borderGradientValues.Zip(borderNormals, ComputeDataTerm);
                var borderPriorities = borderConfidanceValues.Zip(borderDataTerms, (c, d) => c * d)
                                                             .ToArray();

                var currentIndex = borderPriorities.MaxIndex();
                var currentPoint = selectionBorder[currentIndex];
                var currentRect = currentPoint.PointCenteredRectangle(_windowSize);
                var currentRegion = new PixelRgn(drawable, currentRect, true, true);

                var minRgnRect = _pixelDistanceCalc.MinDistanceRegion(currentRect, borderGradientValues[currentIndex], layerPixels,
                                                                      selectionMask);
                var minRgn = new PixelRgn(drawable, minRgnRect, false, false);

                var iterator = new RegionIterator(currentRegion, minRgn);
                iterator.ForEach((targetPixel, srcPixel) =>
                    {
                        if (!selectionMask[targetPixel.X, targetPixel.Y])
                        {
                            return;
                        }
                        layerPixels[targetPixel.X, targetPixel.Y] = srcPixel;
                        targetPixel.Set(srcPixel);
                    });
                drawable.Flush();
                drawable.MergeShadow(true);
                drawable.Update(temp.Selection.MaskBounds);

                //update confidance values
                var currentCoords =
                    RegionHelper.Grid(currentRect).Where(coord => selectionMask[coord.X, coord.Y]).ToArray();
                var newConfidanceValues = NewConfidanceValue(currentCoords, pxConfidenceTerm, _windowSize).ToArray();
                foreach (var point in
                    currentCoords.Zip(newConfidanceValues,
                                      (coordinate, confidance) =>
                                      new {Coordinate = coordinate, Confidance = confidance}))
                {
                    pxConfidenceTerm[point.Coordinate.X, point.Coordinate.Y] = point.Confidance;
                }
                // exclude current region pixels from selection
                selectionMask.SetAreaToZero(currentRect);
                //progress.Update((initArea - selectionMask.Area)/(double) initArea);

                iteration++;
                if (iteration == _iterations)
                {
                    selectionBorder =
                    RegionHelper.TraceBorder(selectionBounds,
                                             coord => selectionMask[coord.X, coord.Y])
                                .ToList();
                    var rgn = new PixelRgn(drawable, selectionBounds, true, true);
                    for (int i = 0; i < selectionBorder.Count; i++)
                    {
                        var coord = selectionBorder[i];
                        rgn.SetPixel(new byte[] { (byte)(255), 0, 0, 255 }, coord.X, coord.Y);
                    }

                    drawable.Flush();
                    drawable.MergeShadow(false);
                    drawable.Update(temp.Selection.MaskBounds);
                }
            }
            temp.Delete();
            image.UndoGroupEnd();
        }
예제 #6
0
 /// <summary>
 /// Calculate data terms for specified coordinates
 /// </summary>
 /// <param name="selectionBorder"></param>
 /// <param name="layerPixels"></param>
 /// <param name="windowSize"></param>
 /// <returns></returns>
 private static IEnumerable<ImgGradient> GradientValues(List<IntCoordinate> selectionBorder, Pixel[,] layerPixels, SelectionMask selection, int windowSize)
 {
     var convolver = new Convolver(ScharrKernel.Instance);
     foreach (var coord in selectionBorder)
     {
         ImgGradient max = null;
         foreach (var sourceCoord in
             RegionHelper.Grid(coord.PointCenteredRectangle(windowSize))
                         .Where(neigbour => !selection[neigbour.X, neigbour.Y]))
         {
             var grad = convolver.Convolve(sourceCoord, layerPixels,
                                           pixel => (pixel.Red + pixel.Green + pixel.Blue)/(1.0*255.0));
             if (max == null)
             {
                 max = grad;
             }
             max = grad.Magnitude > max.Magnitude ? grad : max;
         }
         yield return max;
     }
 }