c#winform利用opencvsharp的Floodfill实现类似PS魔棒功能

    Cv2.FloodFill(),水漫填充算法,是指用指定颜色填充与所选种子点像素的相连区域,常用于图像的分割,标记等。

函数原型:

        //
        // 摘要:
        //     Fills a connected component with the given color.
        //
        // 参数:
        //   image:
        //     Input/output 1- or 3-channel, 8-bit, or floating-point image. It is modified
        //     by the function unless the FLOODFILL_MASK_ONLY flag is set in the second variant
        //     of the function. See the details below.
        //
        //   seedPoint:
        //     Starting point.
        //
        //   newVal:
        //     New value of the repainted domain pixels.
        //
        //   rect:
        //     Optional output parameter set by the function to the minimum bounding rectangle
        //     of the repainted domain.
        //
        //   loDiff:
        //     Maximal lower brightness/color difference between the currently observed pixel
        //     and one of its neighbors belonging to the component, or a seed pixel being added
        //     to the component.
        //
        //   upDiff:
        //     Maximal upper brightness/color difference between the currently observed pixel
        //     and one of its neighbors belonging to the component, or a seed pixel being added
        //     to the component.
        //
        //   flags:
        //     Operation flags. Lower bits contain a connectivity value, 4 (default) or 8, used
        //     within the function. Connectivity determines which neighbors of a pixel are considered.
        public static int FloodFill(InputOutputArray image, Point seedPoint, Scalar newVal, out Rect rect, Scalar? loDiff = default(Scalar?), Scalar? upDiff = default(Scalar?), FloodFillFlags flags = FloodFillFlags.Link4);

winform界面设计:

 实现效果展示:

 

 主要代码以及实现:

我的环境是 VS2015 Opencvsharp3

变量定义:

            //在 yVars.ImgOptions 下
            public struct FloodFill //水漫填充
            {
                // 水漫原图
                public static string Image;
                // 水漫填充颜色
                public static OpenCvSharp.Scalar fillColor = new Scalar();
                // 水漫种子点坐标
                public static OpenCvSharp.Point pointLocation = new OpenCvSharp.Point();
                // 线程启停信号
                public static ManualResetEvent getLocationEvent = new ManualResetEvent(false);
                // 种子点选取标志
                public static bool IsSelectPoint = false;
                public static int loDiff = 0;   // 水漫负差最大值
                public static int upDiff = 0;    // 水漫正差最大值
                //水漫后图片存取队列  用于撤销操作 水漫一次就往此list中添加一张结果图 
                public static List<OpenCvSharp.Mat> matList = new List<Mat>();
                // 更换原图标志位
                public static bool IsChangePic = false;
            }

主要方法:

        public static void ImgFloodFill()
        {
            // 在水漫图片的队列的最后一张图片上进行操作
            Mat pic = new Mat();
            int index = yVars.ImgOptions.FloodFill.matList.Count;
            pic = yVars.ImgOptions.FloodFill.matList[index - 1];

            Mat picOut = new Mat();
            // 水漫图像需要 BGR三通道图片
            Cv2.CvtColor(pic, picOut, ColorConversionCodes.BGRA2BGR);
            OpenCvSharp.Rect re = new Rect();

            // 正负差最大值对应的颜色
            Scalar loDiffColor = new OpenCvSharp.Scalar(yVars.ImgOptions.FloodFill.loDiff, yVars.ImgOptions.FloodFill.loDiff, yVars.ImgOptions.FloodFill.loDiff);
            Scalar upDiffColor = new OpenCvSharp.Scalar(yVars.ImgOptions.FloodFill.upDiff, yVars.ImgOptions.FloodFill.upDiff, yVars.ImgOptions.FloodFill.upDiff);
            // 将在图像种子点位置像素的正负差最大值之间的所有与种子点相连同的所有像素点设置成指定颜色
            Cv2.FloodFill(picOut, yVars.ImgOptions.FloodFill.pointLocation, yVars.ImgOptions.FloodFill.fillColor, out re,
                            loDiffColor, upDiffColor, FloodFillFlags.Link8);

            // 比较水漫前后两张图是否一样  如果一样则不需要添加到队列 方便撤销操作 
            if (!yOthers.matIsEqual(pic, picOut))
            {
                yVars.ImgOptions.FloodFill.matList.Add(picOut);
                Form1.Instance.pbxFloodFill.Image = yImgConvert.MatToBitmap(picOut);
            }
            yVars.ImgOptions.FloodFill.IsSelectPoint = false;
            Form1.Instance.btnSelectPoint.BackColor = Color.Transparent;
            yVars.ImgOptions.FloodFill.pointLocation = new OpenCvSharp.Point(0, 0);
            Form1.Instance.tbxFlood_x.Text = "0";
            Form1.Instance.tbxFlood_y.Text = "0";
            yVars.ImgOptions.FloodFill.getLocationEvent.Reset();
        }

        // 获取种子坐标线程
        // 在点击选择点位之后 当鼠标进入picturebox后 启动下面线程 
        // 当在picturebox上点击鼠标时 暂停下面线程 并将此时鼠标点击位置设置成水漫种子点
        public static Thread GetLocationTask = new Thread(() =>
        {
            while (true)
            {
                int MX = 0, MY = 0;
                OpenCvSharp.Mat mm = new OpenCvSharp.Mat();
                mm = yImgConvert.ImageToMat(Form1.Instance.pbxFloodFill.Image);
                Form1.Instance.Invoke(new Action(() =>
                {
                    // 鼠标相对于picturebox的位置
                    MX = Form1.Instance.pbxFloodFill.PointToClient(Control.MousePosition).X;
                    MY = Form1.Instance.pbxFloodFill.PointToClient(Control.MousePosition).Y;

                    if (MX <= Form1.Instance.pbxFloodFill.Width && MY <= Form1.Instance.pbxFloodFill.Height && MX > 0 && MY > 0)
                    {
                        Form1.Instance.tbxFlood_x.Text = MX.ToString();
                        Form1.Instance.tbxFlood_y.Text = MY.ToString();
                        // 图片是经过缩放后再放入picturebox中 
                        // 大小并不一样 所以需要将相对于picturebox的坐标 转换成相对于对应图片坐标
                        double xx = MX * mm.Width / Form1.Instance.pbxFloodFill.Width;
                        double yy = MY * mm.Height / Form1.Instance.pbxFloodFill.Height;

                        yVars.ImgOptions.FloodFill.pointLocation = new OpenCvSharp.Point(xx, yy);
                    }
                    else
                    {
                        Form1.Instance.tbxFlood_x.Text = "0";
                        Form1.Instance.tbxFlood_y.Text = "0";

                        yVars.ImgOptions.FloodFill.pointLocation = new OpenCvSharp.Point(0, 0);
                    }
                }));
                yVars.ImgOptions.FloodFill.getLocationEvent.WaitOne();
                Thread.Sleep(100);
            }
        });
        // 判断两张多通道图片是否完全一样
        public static bool matIsEqual(Mat mat1, Mat mat2)
        {
            if (mat1.Empty() && mat2.Empty())
            {
                return true;
            }
            if (mat1.Cols != mat2.Cols || mat1.Rows != mat2.Rows || mat1.Dims() != mat2.Dims())
            {
                return false;
            }
            if (mat1.Size() != mat2.Size() || mat1.Channels() != mat2.Channels() || mat1.Type() != mat2.Type())
            {
                return false;
            }
            if (mat1.Total() * mat1.ElemSize() != mat2.Total() * mat2.ElemSize())
            {
                return false;
            }
            Mat tempMat = new Mat();
            Cv2.BitwiseXor(mat1, mat2, tempMat);

            Mat[] mm = Cv2.Split(tempMat);
            foreach (Mat m1 in mm)
            {
                if (Cv2.CountNonZero(m1) != 0)
                    return false;
            }
            return true;
        }

主要控件事件:

        // 选择水漫填充颜色
        private void btnSelectFloodColor_Click(object sender, EventArgs e)
        {
            ColorDialog cc = new ColorDialog();
            if (cc.ShowDialog() == DialogResult.OK)
            {
                yVars.ImgOptions.FloodFill.fillColor = OpenCvSharp.Scalar.FromRgb(cc.Color.R, cc.Color.G, cc.Color.B);
                palFloodColor.BackColor = cc.Color;
            }
        }
        // 选择点位点击事件
        private void btnSelectPoint_Click(object sender, EventArgs e)
        {
            if (yVars.ImgOptions.FloodFill.Image == null)
            {
                YXH._01.yMessagebox.Show_CN("未选择图片");
                return;
            }
            if (yVars.ImgOptions.FloodFill.IsSelectPoint == false)
            {
                yVars.ImgOptions.FloodFill.IsSelectPoint = true;
                btnSelectPoint.BackColor = Color.Green;
                yVars.ImgOptions.FloodFill.IsChangePic = false;
                btnSelectFloodfill.Enabled = false;
            }
            else
            {
                yVars.ImgOptions.FloodFill.IsSelectPoint = false;
                btnSelectPoint.BackColor = Color.Transparent;
            }
        }

        // 点击选择点位按钮后 当鼠标进入picturebox后启动获取鼠标点位的线程
        private void pbxFloodFill_MouseEnter(object sender, EventArgs e)
        {
            if (yVars.ImgOptions.FloodFill.IsSelectPoint == false)
                return;
            if (pbxFloodFill.Image == null)
                return;
            yVars.ImgOptions.FloodFill.getLocationEvent.Set();
            if (!yImgOptions.GetLocationTask.IsAlive)
                yImgOptions.GetLocationTask.Start();
        }

        // picturebo 点击时 暂停线程 画出选择点位
        private void pbxFloodFill_Click(object sender, EventArgs e)
        {
            if (yVars.ImgOptions.FloodFill.pointLocation != null && yVars.ImgOptions.FloodFill.IsSelectPoint == true && yVars.ImgOptions.FloodFill.pointLocation != new OpenCvSharp.Point(0, 0))
            {
                OpenCvSharp.Mat spMat = new OpenCvSharp.Mat();
                spMat = yImgConvert.ImageToMat(Form1.Instance.pbxFloodFill.Image);
                OpenCvSharp.Cv2.Circle(spMat, yVars.ImgOptions.FloodFill.pointLocation, 0, OpenCvSharp.Scalar.Red, 2, LineTypes.AntiAlias);
                pbxFloodFill.Image = yImgConvert.MatToBitmap(spMat);
                btnSelectFloodfill.Enabled = true;
            }
            yVars.ImgOptions.FloodFill.getLocationEvent.Reset();
            yVars.ImgOptions.FloodFill.IsSelectPoint = false;
            btnSelectPoint.BackColor = Color.Transparent;
        }

        // 图像复原
        private void btnResetPic_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(yVars.ImgOptions.FloodFill.Image))
                pbxFloodFill.Image = new Bitmap(yVars.ImgOptions.FloodFill.Image);
        }

      // 撤销操作 从水漫图片队列中 选择倒数第二张显示 并删除最后一张
        private void btnRepeal_Click(object sender, EventArgs e)
        {
            int index = 0;
            index = yVars.ImgOptions.FloodFill.matList.Count;
            if (index <= 1)
                return;
            else if (index > 1)
            {
                yVars.ImgOptions.FloodFill.matList.RemoveAt(index - 1);
                index = yVars.ImgOptions.FloodFill.matList.Count;
                Form1.Instance.pbxFloodFill.Image = yImgConvert.MatToBitmap(yVars.ImgOptions.FloodFill.matList[index - 1]);
            }
        }

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要在 WinForms 中配置 OpenCvSharp,您可以按照以下步骤进行操作: 1. 首先,确保已经安装了 OpenCvSharp 库。您可以在 NuGet 包管理器中搜索并安装 "OpenCvSharp4"。 2. 在您的 WinForms 项目中,右键单击项目名称,然后选择 "管理 NuGet 包"。在 NuGet 包管理器中搜索并安装 "OpenCvSharp4"。 3. 确保您的项目引用了正确的命名空间。在您的代码文件的顶部添加以下引用语句: ```csharp using OpenCvSharp; ``` 4. 在您的 WinForms 窗体上添加一个 PictureBox 控件,用于显示图像。 5. 创建一个按钮或其他触发事件的控件,以加载和处理图像。 6. 在按钮的点击事件处理程序中,添加以下代码来加载和显示图像: ```csharp private void LoadAndDisplayImage() { OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "Image Files (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp"; if (openFileDialog.ShowDialog() == DialogResult.OK) { Mat image = new Mat(openFileDialog.FileName); pictureBox.Image = image.ToBitmap(); } } ``` 上述代码会打开一个文件对话框,允许用户选择图像文件。选择的图像会加载到一个 `Mat` 对象中,并将其转换为 `Bitmap` 格式以便在 PictureBox 控件中显示。 请注意,您可能还需要根据您的具体需求添加其他 OpenCvSharp 的图像处理代码。上述代码仅提供了一个简单的示例,用于加载和显示图像。 希望这可以帮助您在 WinForms 中配置 OpenCvSharp!如有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值