c#-OpenCvSharp-roi区域(截取和掩码)附源码

 根据前两篇博客roi截图和掩码操作进行总结优化,涉及到的知识点讲解都在两篇文章中,这里不多加赘述,该文章仅作为总结。

OpenCvSharp-鼠标框选截取感兴趣区域(ROI)-附源代码

c#-OpenCvSharp-掩码操作(附源码)

仅在鼠标移动事件中加入掩码操作,感觉代码还有优化的地方,后面会回头继续优化。各位读者有对代码进行优化的话可以联系我,一起交流学习,作为初学者,我还要很多需要学习的地方。

以下是代码

using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Point = OpenCvSharp.Point;

namespace 绘制ROI_掩码_
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Mat src;// 存储图像的Mat对象

        //选择图像文件
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Image Files(*.jpg;*.png*;*.bmp*)|*.jpg;*.png*;*.bmp";
            if (ofd.ShowDialog() != DialogResult.OK)
                return;
            string imagePath = ofd.FileName;
            src = Cv2.ImRead(imagePath, ImreadModes.AnyColor);
            Cv2.ImShow("src image", src);
        }


        static Mat tempMat; // 用于临时存储原始图像
        static Point sp = new Point(-1, -1); // 起始点坐标
        static Point ep = new Point(-1, -1); // 终点坐标

        private void button2_Click(object sender, EventArgs e)
        {
            if (src == null)
            {
                MessageBox.Show("请先选择图像文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            // 创建鼠标回调函数
            MouseCallback draw = new MouseCallback(DrawRectangle);


            // 复制图像
            tempMat = new Mat(src.Size(), src.Type());
            Cv2.CopyTo(src, tempMat);

            // 分两步将Mat对象转换为IntPtr,用于传递给回调函数。
            // 将Mat对象src作为参数传递给Alloc方法,以创建一个GCHandle对象,并将其与srcImage关联起来
            System.Runtime.InteropServices.GCHandle handle = System.Runtime.InteropServices.GCHandle.Alloc(src);

            // 再将GCHandle对象转换为IntPtr,即从GCHandle对象中获取对象所在的内存地址。
            IntPtr ptr = System.Runtime.InteropServices.GCHandle.ToIntPtr(handle);

            // 设置鼠标回调函数,将ptr作为额外的用户数据,通过Cv2.SetMouseCallback方法传递给鼠标回调函数DrawRectangle
            Cv2.SetMouseCallback("src image", draw, ptr);
            Cv2.WaitKey();
        }

        // 鼠标回调函数DrawRectangle,它是一个委托类型MouseCallback的实现
        public static void DrawRectangle(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userData)
        {
            // 获取图像数据 从userData指针中获取用户数据,并将其转换为GCHandle对象
            System.Runtime.InteropServices.GCHandle handle = System.Runtime.InteropServices.GCHandle.FromIntPtr(userData);
            Mat src = (Mat)handle.Target;

            // 鼠标左键按下事件
            if (@event == MouseEventTypes.LButtonDown)
            {
                sp.X = x;
                sp.Y = y;
                Console.WriteLine("起点坐标 ({0},{1})", sp.X, sp.Y);
            }
            // 鼠标左键抬起事件
            else if (@event == MouseEventTypes.LButtonUp)
            {
                ep.X = x;
                ep.Y = y;
                Console.WriteLine("终点坐标 ({0},{1})", ep.X, ep.Y);

                // 绘制矩形
                if (ep.X > sp.X && ep.Y > sp.Y)
                {
                    // Cv2.Rectangle方法用于在图像(Mat对象)上绘制矩形 
                    // Cv2.Rectangle(Mat img, Point pt1, Point pt2, Scalar color, int thickness = 1, LineTypes lineType = LineTypes.Link8, int shift = 0);
                    Cv2.Rectangle(src, sp, ep, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias, 0);

                    // 用SubMat()提取子区域,该代码用来显示截取出来的图片
                    Cv2.ImShow("ROI区域", src.SubMat(sp.Y, ep.Y, sp.X, ep.X));

                    // 显示绘制矩形后的图像
                    Cv2.ImShow("src image", src);

                    // 完成绘制矩形后,sp.X和sp.Y重置为-1。确保下一次绘制矩形时能够正确记录起点坐标
                    sp.X = -1;
                    sp.Y = -1;
                }
            }


            // 鼠标移动事件 (加入掩码操作部分)
            else if (@event == MouseEventTypes.MouseMove && sp.X > 0 && sp.Y > 0)
            {
                ep.X = x;
                ep.Y = y;

                if (ep.X > sp.X && ep.Y > sp.Y)
                {
                    // 创建临时图像并将原始图像复制到临时图像中
                    Mat tempMat = new Mat();  
                    src.CopyTo(tempMat);     

                    // 计算矩形区域
                    Rect roi = new Rect(sp.X, sp.Y, ep.X - sp.X, ep.Y - sp.Y);
                   
                    // 创建掩码并将矩形区域设为非零值
                    Mat mask = new Mat(src.Size(), MatType.CV_8UC1, Scalar.All(0));

                    // 将矩形区域在掩码中设为非零值(255),这个矩形区域将被用于后续的掩码操作
                    mask[roi].SetTo(new Scalar(255));
                   
                    // 应用掩码并显示结果
                    Mat result = new Mat();  // 创建一个空的Mat对象,用于存储掩码操作后的结果
                    tempMat.CopyTo(result, mask);

                    // 显示经过掩码操作后的图像 result,即只显示矩形区域内的内容,其他区域被掩盖
                    Cv2.ImShow("Masked Image", result);
                   
                }
            }

        }
    }
}

猜你喜欢

转载自blog.csdn.net/m0_55074196/article/details/132064485
今日推荐