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; }
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(); }
/// <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; } }