前言:ROI(Region of Interest)是图像处理中的一个重要概念,指的是图像中感兴趣的区域。在这个区域内,我们通常希望执行某种特定的操作、获取特定信息,或者进行进一步的分析。ROI 可以是图像的一个矩形、圆形、多边形或者其他各种形状。
目录
一、核心函数:
委托 MouseCallback
设置鼠标回调函数 Cv2.SetMouseCallback()
绘制矩形 Cv2.Rectangle()
提取子区域 SubMat():
二、操作步骤
三、源代码如下
public delegate void MouseCallback(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userdata);
这个委托类型定义了一个鼠标回调函数的格式,回调函数需要接收五个参数
@event
:鼠标事件类型,它是一个枚举类型MouseEventTypes
,表示鼠标的不同操作,例如按下、抬起、移动等。x
和y
:鼠标操作发生的位置坐标,它们表示鼠标在图像窗口上的位置。flags
:鼠标事件的附加标志,它是一个枚举类型MouseEventFlags
,用于描述鼠标事件的一些附加信息。userData
:这是一个指向用户数据的指针,用于传递额外的数据到回调函数中。Cv2.SetMouseCallback(string winname, MouseCallback onMouse, IntPtr userdata = default(IntPtr))
winname
:图像窗口的名称,在该窗口上监听鼠标事件。onMouse
:表示注册的鼠标回调函数,是一个委托类型MouseCallback
,当鼠标事件发生时,将调用该函数。userdata
:可选参数,传递给回调函数的额外用户数据,默认为default(IntPtr)
,如果不需要传递额外数据,可以不提供。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。Mat SubMat(int y, int height, int x, int width);
y
: 表示子区域的起始行索引。height
: 表示子区域的高度。x
: 表示子区域的起始列索引。width
: 表示子区域的宽度。SubMat
方法返回一个新的Mat对象,该对象表示从原始图像中提取出的子区域。子区域实际上是从原始图像中截取出的矩形区域。
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);
}
}
}
}
}