C#如何让洪水填充工作过的颜色渐变?

问题描述 投票:1回答:2

我不是很在C#中还经历,并有写一洪水填充算法时,有颜色的微小变化(就像图片中的阴影)也有效。我发现我修饰也改变具有在RGB-光谱比以前(整个“RGB试验”部分)的一个稍微不同的值的像素基于堆栈的4路算法,而不是仅一个区域与单个颜色:

private void FloodFill2(Bitmap bmp, Point pt, Color targetColor, Color replacementColor)
    {
        Stack<Point> pixels = new Stack<Point>();
        pixels.Push(pt);

        while (pixels.Count > 0)
        {
            Point a = pixels.Pop();
            if (a.X < bmp.Width && a.X > 0 &&
                    a.Y < bmp.Height && a.Y > 0)//make sure we stay within bounds
            {
                // RGB-Test Start
                green = false;
                red = false;
                blue = false;

                if (bmp.GetPixel(a.X, a.Y).G > targetColor.G)
                {
                    if (targetColor.G - bmp.GetPixel(a.X, a.Y).G > (-20))
                    {
                        green = true;
                    }
                }
                else
                {
                    if (bmp.GetPixel(a.X, a.Y).G - targetColor.G > (-20))
                    {
                        green = true;
                    }
                }

                if (bmp.GetPixel(a.X, a.Y).R > targetColor.R)
                {
                    if (targetColor.R - bmp.GetPixel(a.X, a.Y).R > (-20))
                    {
                        red = true;
                    }
                }
                else
                {
                    if (bmp.GetPixel(a.X, a.Y).R - targetColor.R > (-20))
                    {
                        red = true;
                    }
                }

                if (bmp.GetPixel(a.X, a.Y).B > targetColor.B)
                {
                    if (targetColor.B - bmp.GetPixel(a.X, a.Y).B > (-20))
                    {
                        blue = true;
                    }
                }
                else
                {
                    if (bmp.GetPixel(a.X, a.Y).B - targetColor.B > (-20))
                    {
                        blue = true;
                    }
                }
                // RGB-Test End

                if (red == true && blue == true && green == true)
                { 
                    bmp.SetPixel(a.X, a.Y, replacementColor);
                    pixels.Push(new Point(a.X - 1, a.Y));
                    pixels.Push(new Point(a.X + 1, a.Y));
                    pixels.Push(new Point(a.X, a.Y - 1));
                    pixels.Push(new Point(a.X, a.Y + 1));
                }
            }
        }
        //refresh our main picture box
        pictureBox1.Image = bmp;
        pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
        return;
    }    

现在的问题是,如果图像中的梯度变得太强大了,然后像这样将停止:https://i.stack.imgur.com/15jhd.png

作为一个解决方案,我想改变“targetColor”到当前正在改变的像素的新颜色,使之能“游”过梯度,只有停止,如果有突然过大的色差的。

但这里说到的我与一般堆和c#小知识问题,因为修改这样的代码,这部分的第一次尝试

if (red == true && blue == true && green == true)
                { 
                    newColor = bmp.GetPixel(a.X, a.Y); // added this
                    bmp.SetPixel(a.X, a.Y, replacementColor);
                    pixels.Push(new Point(a.X - 1, a.Y));
                    pixels.Push(new Point(a.X + 1, a.Y));
                    pixels.Push(new Point(a.X, a.Y - 1));
                    pixels.Push(new Point(a.X, a.Y + 1));
                    targetColor = newColor; // and this
                }

我得到的结果看起来就像是:https://i.stack.imgur.com/U52mF.png

这是奇怪的,因为它不正是它应该只是不用到处它应该只有在整个画面上有些条纹的形式。

我感谢你们每一个解决方案,并就如何使这项工作正确其他的想法。

c# flood-fill
2个回答
1
投票

我对这个问题的办法是也存储在有关的颜色,当加点,从而例如堆栈被检查堆栈信息我们检查与颜色(255,10,1)像素(10,15),并在我们添加了关于以前的颜色(10,15)信息堆栈像素(10,16),并且像素检查过程中,我们比较了颜色上一个。改变我做:

1)包括关于在堆先前像素的颜色信息:针对我用C#构建体命名touple:

Stack<(Point point, Color target)> pixels = new Stack<(Point, Color)>();
pixels.Push((pt, target));

2)栈工作时,我们得到对像素/ targetColour

    var curr = pixels.Pop();
    var a = curr.point;
    Color targetColor = curr.target;

3)虽然加分堆,我们也包括老像素颜色:

var old = bmp.GetPixel(a.X, a.Y);
bmp.SetPixel(a.X, a.Y, replacementColor);
pixels.Push((new Point(a.X - 1, a.Y), old));
pixels.Push((new Point(a.X + 1, a.Y), old));
pixels.Push((new Point(a.X, a.Y - 1), old));
pixels.Push((new Point(a.X, a.Y + 1), old));

一些重构后的代码:

void FloodFill2(Bitmap bmp, Point pt, Color target, Color replacementColor)
{
    Stack<(Point point, Color target)> pixels = new Stack<(Point, Color)>();
    pixels.Push((pt, target));

    while (pixels.Count > 0)
    {
        var curr = pixels.Pop();
        var a = curr.point;
        Color targetColor = curr.target;

        if (a.X < bmp.Width && a.X > 0 &&
                a.Y < bmp.Height && a.Y > 0)//make sure we stay within bounds
        {
            var tolerance = 10;
            var green = Math.Abs(targetColor.G - bmp.GetPixel(a.X, a.Y).G) < tolerance;
            var red = Math.Abs(targetColor.R - bmp.GetPixel(a.X, a.Y).R) < tolerance;
            var blue = Math.Abs(targetColor.B - bmp.GetPixel(a.X, a.Y).B) < tolerance;

            if (red == true && blue == true && green == true)
            {
                var old = bmp.GetPixel(a.X, a.Y);
                bmp.SetPixel(a.X, a.Y, replacementColor);
                pixels.Push((new Point(a.X - 1, a.Y), old));
                pixels.Push((new Point(a.X + 1, a.Y), old));
                pixels.Push((new Point(a.X, a.Y - 1), old));
                pixels.Push((new Point(a.X, a.Y + 1), old));
            }
        }
    }
    //refresh our main picture box
    pictureBox1.Image = bmp;
    pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
    return;
}

最终效果:

Final effect


0
投票

如果像我一样,接受的答案是不是为你工作:下面试试这个修改后的代码:它是非常相似的@Adam除公差maleks的答案发送到方法(而不是硬编码的),也Stack一直分裂成两个对象,以防止一种类型的错误。

    private Bitmap floodfill(Bitmap input, Point pt, Color target, Color replacementColor, int r_tol, int g_tol, int b_tol)
    {
        Stack<Point> pixels = new Stack<Point>();
        Stack<Color> colour = new Stack<Color>();

        pixels.Push(pt);
        colour.Push(target);

        while (pixels.Count > 0)
        {

            var current_pixels = pixels.Pop();
            var current_colour = colour.Pop();
            var a = new Point(current_pixels.X, current_pixels.Y);
            Color targetColor = current_colour;

            if (a.X < input.Width && a.X > 0 && a.Y < input.Height && a.Y > 0)
            {
                var green = Math.Abs(targetColor.G - input.GetPixel(a.X, a.Y).G) < r_tol;
                var red = Math.Abs(targetColor.R - input.GetPixel(a.X, a.Y).R) < g_tol;
                var blue = Math.Abs(targetColor.B - input.GetPixel(a.X, a.Y).B) < b_tol;

                if (red == true && blue == true && green == true)
                {
                    var old_pixels = input.GetPixel(a.X, a.Y);
                    input.SetPixel(a.X, a.Y, replacementColor);
                    pixels.Push(new Point(a.X - 1, a.Y));
                    colour.Push(old_pixels);
                    pixels.Push(new Point(a.X + 1, a.Y));
                    colour.Push(old_pixels);
                    pixels.Push(new Point(a.X, a.Y - 1));
                    colour.Push(old_pixels);
                    pixels.Push(new Point(a.X, a.Y + 1));
                    colour.Push(old_pixels);
                }
            }
        }

        return input;
    }
© www.soinside.com 2019 - 2024. All rights reserved.