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

 前言:ROI(Region of Interest)是图像处理中的一个重要概念,指的是图像中感兴趣的区域。在这个区域内,我们通常希望执行某种特定的操作、获取特定信息,或者进行进一步的分析。ROI 可以是图像的一个矩形、圆形、多边形或者其他各种形状。

目录

一、核心函数:

委托 MouseCallback

设置鼠标回调函数 Cv2.SetMouseCallback()

绘制矩形 Cv2.Rectangle()

提取子区域 SubMat():

二、操作步骤

三、源代码如下


一、核心函数:

委托 MouseCallback
public delegate void MouseCallback(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userdata);

 这个委托类型定义了一个鼠标回调函数的格式,回调函数需要接收五个参数

  • @event:鼠标事件类型,它是一个枚举类型MouseEventTypes,表示鼠标的不同操作,例如按下、抬起、移动等。
  • xy:鼠标操作发生的位置坐标,它们表示鼠标在图像窗口上的位置。
  • flags:鼠标事件的附加标志,它是一个枚举类型MouseEventFlags,用于描述鼠标事件的一些附加信息。
  • userData:这是一个指向用户数据的指针,用于传递额外的数据到回调函数中。

设置鼠标回调函数 Cv2.SetMouseCallback()
Cv2.SetMouseCallback(string winname, MouseCallback onMouse, IntPtr userdata = default(IntPtr))
  • winname:图像窗口的名称,在该窗口上监听鼠标事件。
  • onMouse:表示注册的鼠标回调函数,是一个委托类型MouseCallback,当鼠标事件发生时,将调用该函数。
  • userdata:可选参数,传递给回调函数的额外用户数据,默认为default(IntPtr),如果不需要传递额外数据,可以不提供。
绘制矩形 Cv2.Rectangle()
void Cv2.Rectangle(Mat img, Point pt1, Point pt2, Scalar color, int thickness = 1, LineTypes lineType = LineTypes.Link8, int shift = 0);
  • img: 表示源图像(Mat对象),在其中绘制矩形。
  • pt1: 表示矩形左上角的坐标点(Point对象)。
  • pt2: 表示矩形右下角的坐标点(Point对象)。
  • color: 表示绘制矩形的颜色,以BGR格式表示(Scalar对象)。
  • thickness: 可选参数,指定绘制矩形线条的厚度,默认值为1。
  • lineType: 可选参数,指定绘制矩形线条的类型,默认值为LineTypes.Link8,表示8连通线。
  • shift: 可选参数,指定坐标点的小数部分位数,默认值为0。
提取子区域 SubMat():
Mat SubMat(int y, int height, int x, int width);
  • y: 表示子区域的起始行索引。
  • height: 表示子区域的高度。
  • x: 表示子区域的起始列索引。
  • width: 表示子区域的宽度。

SubMat方法返回一个新的Mat对象,该对象表示从原始图像中提取出的子区域。子区域实际上是从原始图像中截取出的矩形区域。

二、操作步骤

 1.创建窗体程序、设置两个按钮

OpenCvSharp-鼠标框选截取感兴趣区域(ROI)-附源代码_第1张图片

  2.Ctrl C + V

三、源代码如下

using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Windows.Forms;
using Point = OpenCvSharp.Point;

namespace 绘制roi
{
    public partial class Form1 : System.Windows.Forms.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方法用于从图像(Mat对象)中提取子区域,Mat SubMat(int y, int height, int x, int width);
                    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)
                {
                    // 将临时图像tempMat复制到src中
                    Cv2.CopyTo(tempMat, src);
                    // 在src图像上绘制矩形
                    Cv2.Rectangle(src, sp, ep, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias, 0);
                    Cv2.ImShow("src image", src);
                }
            }
        }
    }
}

你可能感兴趣的:(c#,opencv,计算机视觉)