如何用颜色填充部分图像?

时间:2017-07-24 21:23:50

标签: c#

我有我在形式中添加的图像。我如何填写图像的一部分?

我有这个

I have this

我想要实现的目标:

What i want have

1 个答案:

答案 0 :(得分:3)

floodfill 一个区域,你需要一个食品填充程序而且很少。

见这个例子:

enter image description here

它使用两个图片框,也是一个显示所选颜色的标签。

两个鼠标点击事件,一个用于选择颜色:

private void pictureBoxPalette_MouseClick(object sender, MouseEventArgs e)
{
    Point sPt = scaledPoint(pictureBoxPalette, e.Location);
    lbl_color.BackColor = ((Bitmap)pictureBoxPalette.Image).GetPixel(sPt.X, sPt.Y);
}

..和一个叫填充:

private void pictureBoxTgt_MouseClick(object sender, MouseEventArgs e)
{
    Point sPt = scaledPoint(pictureBoxTgt, e.Location);
    Bitmap bmp = (Bitmap)pictureBoxTgt.Image;
    Color c0 = bmp.GetPixel(sPt.X, sPt.Y); 
    Fill4(bmp, sPt, c0, lbl_color.BackColor);
    pictureBoxTgt.Image = bmp;
}

Floodfill例程取自this post;它基本上是wikipedia算法的直接实现..:

static void Fill4(Bitmap bmp, Point pt, Color c0, Color c1)
{
    Color cx = bmp.GetPixel(pt.X, pt.Y);
    if (cx.GetBrightness() < 0.01f) return;  // optional, to prevent filling a black grid
    Rectangle bmpRect = new Rectangle(Point.Empty, bmp.Size);
    Stack<Point> stack = new Stack<Point>();
    int x0 = pt.X;
    int y0 = pt.Y;

    stack.Push(new Point(x0, y0) );
    while (stack.Any() )
    {
        Point p = stack.Pop();
        if (!bmpRect.Contains(p)) continue;
        cx = bmp.GetPixel(p.X, p.Y);
        if (cx == c0)
        {
            bmp.SetPixel(p.X, p.Y, c1);
            stack.Push(new Point(p.X, p.Y + 1));
            stack.Push(new Point(p.X, p.Y - 1));
            stack.Push(new Point(p.X + 1, p.Y));
            stack.Push(new Point(p.X - 1, p.Y));
        }
    }
}

更新

我已经更新了代码,以包含一个将鼠标点击位置缩放到图像像素点的功能;现在它也适用于SizeMode=StretchImage,因此您可以处理整个图像..

static Point scaledPoint(PictureBox pb, Point pt)
{
    float scaleX = 1f * pb.Image.Width / pb.ClientSize.Width;
    float scaleY = 1f * pb.Image.Height / pb.ClientSize.Height;
    return  new Point((int)(pt.X * scaleX), (int)(pt.Y * scaleY));
}

当然,您可以保存图像。

请注意,原始图像为4bpp,在着色之前必须转换为24bpp或更高。

另请注意,对于SizeMode=Zoom,计算更复杂一些。以下示例适用于任何SizeMode。:

static Point scaledPoint(PictureBox pbox, Point pt)
{
    Size si = pbox.Image.Size;
    Size sp = pbox.ClientSize;
    int left = 0;
    int top = 0;

    if (pbox.SizeMode == PictureBoxSizeMode.Normal ||
        pbox.SizeMode == PictureBoxSizeMode.AutoSize) return pt;
    if (pbox.SizeMode == PictureBoxSizeMode.CenterImage)
    {
        left = (sp.Width - si.Width) / 2;
        top = (sp.Height - si.Height) / 2;
        return new Point(pt.X - left, pt.Y - top);
    }                   
    if (pbox.SizeMode == PictureBoxSizeMode.Zoom)
    {
        if (1f * si.Width / si.Height < 1f * sp.Width / sp.Height)
            left = (sp.Width - si.Width * sp.Height / si.Height) / 2;
        else
            top = (sp.Height - si.Height * sp.Width / si.Width) / 2;
    }

    pt = new Point(pt.X  - left, pt.Y - top);
    float scaleX = 1f * pbox.Image.Width / (pbox.ClientSize.Width - 2 * left) ;
    float scaleY = 1f * pbox.Image.Height / (pbox.ClientSize.Height - 2 * top);
    return new Point((int)(pt.X * scaleX), (int)(pt.Y * scaleY));
}