图像填充算法--洪水填充FloodFill



  

    洪水填充算法也叫种子生长算法,洪水填充算法是在很多图形绘制软件中常用的填充算法,比如Windows paint的油漆桶功能,这个算法的实现有多种方式,比如递归实现,扫描线算法等等,基于像素四邻域/八邻域等,本文基于四邻域实现,主要算法步骤如下:

1,在图像中选择一个种子点,如下图所示:

                        

                                Fig.1示意图

    种子点为图像中的黑色方框,即黑色像素点。

2,以这个点为起点,将它压入栈中,假设我们要填充的颜色为A,则将该点颜色设置为A,然后判断它的四邻域像素,这里我们设置一个颜色阈值T,假设当前像素灰度值为P(x,y),四邻域像素为M(n),n=1,2,3,4,那么判断当前像素与四邻域像素的灰度差值D=|P-M|,如果D小于T, 那么我们将该像素M作为下一个种子点,压入栈中,否则继续判断。如图中黑色像素的四邻域内有一灰色点,与其差值小于T,则把它作为新的种子点压入栈中,继续判断。

3,当栈为空时,种子填充结束,否则重做步骤2

    主要函数实现代码如下所示:

        /// <summary>
        /// Flood fill algorithm.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <param name="location">The start point.</param>
        /// <param name="fillColor">The color to be filled.</param>
        /// <param name="threshould">One parameter to control fill effect,from 0 to 255.</param>
        /// <returns></returns>
        public Bitmap FloodFill(Bitmap src, Point location, Color fillColor, int threshould)
        {
            try
            {
                Bitmap a = new Bitmap(src);
                int w = a.Width;
                int h = a.Height;
                Stack<Point> fillPoints = new Stack<Point>(w * h);
                System.Drawing.Imaging.BitmapData bmpData = a.LockBits(new Rectangle(0, 0, a.Width, a.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                IntPtr ptr = bmpData.Scan0;
                int stride = bmpData.Stride;
                int bytes = bmpData.Stride * a.Height;
                byte[] grayValues = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
                byte[] temp = (byte[])grayValues.Clone();
                Color backColor = Color.FromArgb(temp[location.X * 3 + 2 + location.Y * stride], temp[location.X * 3 + 1 + location.Y * stride], temp[location.X * 3 + location.Y * stride]);
                int gray = (int)((backColor.R + backColor.G + backColor.B) / 3);
                if (location.X < 0 || location.X >= w || location.Y < 0 || location.Y >= h) return null;
                fillPoints.Push(new Point(location.X, location.Y));
                int[,] mask = new int[w, h];
                while (fillPoints.Count > 0)
                {
                    Point p = fillPoints.Pop();
                    mask[p.X, p.Y] = 1;
                    temp[3 * p.X + p.Y * stride] = (byte)fillColor.B;
                    temp[3 * p.X + 1 + p.Y * stride] = (byte)fillColor.G;
                    temp[3 * p.X + 2 + p.Y * stride] = (byte)fillColor.R;
                    if (p.X > 0 && (Math.Abs(gray - (int)((temp[3 * (p.X - 1) + p.Y * stride] + temp[3 * (p.X - 1) + 1 + p.Y * stride] + temp[3 * (p.X - 1) + 2 + p.Y * stride]) / 3)) < threshould) && (mask[p.X - 1, p.Y] != 1))
                    {
                        temp[3 * (p.X - 1) + p.Y * stride] = (byte)fillColor.B;
                        temp[3 * (p.X - 1) + 1 + p.Y * stride] = (byte)fillColor.G;
                        temp[3 * (p.X - 1) + 2 + p.Y * stride] = (byte)fillColor.R;
                        fillPoints.Push(new Point(p.X - 1, p.Y));
                        mask[p.X - 1, p.Y] = 1;
                    }
                    if (p.X < w - 1 && (Math.Abs(gray - (int)((temp[3 * (p.X + 1) + p.Y * stride] + temp[3 * (p.X + 1) + 1 + p.Y * stride] + temp[3 * (p.X + 1) + 2 + p.Y * stride]) / 3)) < threshould) && (mask[p.X + 1, p.Y] != 1))
                    {
                        temp[3 * (p.X + 1) + p.Y * stride] = (byte)fillColor.B;
                        temp[3 * (p.X + 1) + 1 + p.Y * stride] = (byte)fillColor.G;
                        temp[3 * (p.X + 1) + 2 + p.Y * stride] = (byte)fillColor.R;
                        fillPoints.Push(new Point(p.X + 1, p.Y));
                        mask[p.X + 1, p.Y] = 1;
                    }
                    if (p.Y > 0 && (Math.Abs(gray - (int)((temp[3 * p.X + (p.Y - 1) * stride] + temp[3 * p.X + 1 + (p.Y - 1) * stride] + temp[3 * p.X + 2 + (p.Y - 1) * stride]) / 3)) < threshould) && (mask[p.X, p.Y - 1] != 1))
                    {
                        temp[3 * p.X + (p.Y - 1) * stride] = (byte)fillColor.B;
                        temp[3 * p.X + 1 + (p.Y - 1) * stride] = (byte)fillColor.G;
                        temp[3 * p.X + 2 + (p.Y - 1) * stride] = (byte)fillColor.R;
                        fillPoints.Push(new Point(p.X, p.Y - 1));
                        mask[p.X, p.Y - 1] = 1;
                    }
                    if (p.Y < h - 1 && (Math.Abs(gray - (int)((temp[3 * p.X + (p.Y + 1) * stride] + temp[3 * p.X + 1 + (p.Y + 1) * stride] + temp[3 * p.X + 2 + (p.Y + 1) * stride]) / 3)) < threshould) && (mask[p.X, p.Y + 1] != 1))
                    {
                        temp[3 * p.X + (p.Y + 1) * stride] = (byte)fillColor.B;
                        temp[3 * p.X + 1 + (p.Y + 1) * stride] = (byte)fillColor.G;
                        temp[3 * p.X + 2 + (p.Y + 1) * stride] = (byte)fillColor.R;
                        fillPoints.Push(new Point(p.X, p.Y + 1));
                        mask[p.X, p.Y + 1] = 1;
                    }
                }
                fillPoints.Clear();
                grayValues = (byte[])temp.Clone();
                System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
                a.UnlockBits(bmpData);
                return a;
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
                return null;
            }
        }

    最后给个Demo的例子,免费下载地址:点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trent1985

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值