一、函数:
a.setMouseCallback
函数:
(1)函数原型:
-
CV_EXPORTS void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);
(2)参数:
winname
:窗口的名称,这个名称将用于识别窗口。onMouse
:鼠标事件的回调函数。当鼠标在指定窗口内移动、点击或释放时,将调用此函数。回调函数需要符合特定的签名,并能够处理不同类型的鼠标事件。userdata
:这是一个可选参数,允许传递自定义数据给回调函数。如果不需要传递数据,可以使用默认值nullptr
。
(3)回调函数:
- 回调函数
onMouse
的原型通常如下所示:
void onMouse(int event, int x, int y, int flags, void* userdata);
- 参数解释:
event
:表示鼠标事件的类型,例如鼠标按下、释放、移动等。x
和y
:鼠标事件相对于窗口左上角的坐标。flags
:表示鼠标事件的附加信息,例如哪个按钮被按下。userdata
:这是传递给setMouseCallback
的自定义数据,可以在回调函数内部使用。
(4)用途:
-
setMouseCallback
函数允许开发者为OpenCV窗口定义自定义的鼠标行为,这在创建交互式应用程序时非常有用,例如绘制图形、选择区域、调整参数等。
b.drawContours
函数:
(1)函数作用:
-
drawContours
函数用于在图像上绘制轮廓的轮廓线或填充轮廓的区域。
(2)参数:
image
:目标图像,即绘制轮廓的图像。contours
:所有输入轮廓的集合。每个轮廓存储为点的向量。contourIdx
:指定要绘制的轮廓的索引。如果是负数,则绘制所有轮廓。color
:轮廓的颜色。thickness
:绘制轮廓线时的线条厚度。如果为负值(例如,thickness=FILLED
),则填充轮廓内部。lineType
:线条的连通性类型,参考LineTypes
。hierarchy
:可选的关于轮廓层次的信息。仅在需要绘制部分轮廓时(见maxLevel
)才需要。maxLevel
:绘制轮廓的最大层次。如果为0,只绘制指定的轮廓。如果为1,绘制该轮廓和所有嵌套轮廓。如果为2,绘制轮廓、所有嵌套轮廓、所有嵌套到嵌套的轮廓,等等。offset
:可选的轮廓偏移参数。将所有绘制的轮廓按指定的offset=(dx,dy)
偏移。
(3)注意事项:
- 当
thickness=FILLED
时,即使没有提供层次数据,该函数也能正确处理具有孔洞的连通组件,使用偶-奇规则分析所有轮廓线。 - 如果你有一个单独检索到的轮廓的集合,直接使用
drawContours
可能会得到错误的结果。为了解决这个问题,需要对每个轮廓子组分别调用drawContours
,或者使用contourIdx
参数迭代遍历轮廓集合。
二、示例代码:
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
// 定义存储鼠标点击点的向量和单个点的结构
std::vector<Point> mousePoints;
Point points;
// 声明选择多边形区域的函数
int selectPolygon(cv::Mat srcMat, cv::Mat& dstMat);
// 声明鼠标响应函数
void Mouse_response(int EVENT, int x, int y, int flags, void* userdata);
int main() {
// 设置日志级别为不输出任何日志信息
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
// 读取图像文件,以灰度模式读取
Mat srcMat = imread("C:\\Users\\86173\\Desktop\\TI\\Q版阿离.png", 0);
// 定义用于存储感兴趣区域(ROI)图像的Mat对象
Mat ROI_image;
// 检查图像是否成功加载
if (srcMat.empty()) {
cout << "failed to read image!:" << endl;
return -1;
}
// 调用函数,通过鼠标选择在图像上定义一个多边形区域
selectPolygon(srcMat, ROI_image);
// 显示选择的多边形区域
imshow("感兴趣区域(ROI)", ROI_image);
// 等待用户按键后关闭窗口
waitKey(0);
return 0;
}
// 定义selectPolygon函数,通过鼠标交互在图像上选择一个多边形区域
int selectPolygon(Mat srcMat, Mat& ROI_image) {
// 定义存储多边形顶点的向量和掩码矩阵
vector<vector<Point>> contours;
Mat mouse_image;
// 初始化掩码矩阵,大小与srcMat相同,类型为CV_32F,初始值为0
Mat Mask_matrix = Mat::zeros(srcMat.size(), CV_32F);
// 检查图像是否成功加载
if (!srcMat.empty()) {
// 复制srcMat到mouse_image和ROI_image
srcMat.copyTo(mouse_image);
srcMat.copyTo(ROI_image);
} else {
cout << "failed to read image!:" << endl;
return -1;
}
// 创建显示图像的窗口
namedWindow("mouseCallback");
imshow("mouseCallback", mouse_image);
// 设置鼠标回调函数,当鼠标在"mouseCallback"窗口中有动作时,调用Mouse_response函数
setMouseCallback("mouseCallback", Mouse_response, &mouse_image);
// 等待用户完成鼠标操作
waitKey(0);
destroyAllWindows();
// 将鼠标点击的点存入contours向量中
contours.push_back(mousePoints);
// 检查点的数量是否足够构成多边形(至少需要3个点)
if (contours[0].size() < 3) {
cout << "failed to read image!:" << endl;
return -1;
}
// 使用drawContours函数在Mask_matrix上绘制多边形
drawContours(Mask_matrix, contours, 0, Scalar(1), -1);
// 将掩码矩阵复制到ROI_image
Mask_matrix.copyTo(ROI_image);
return 0;
}
// 定义鼠标响应函数Mouse_response
void Mouse_response(int EVENT, int x, int y, int flags, void* userdata) {
// 将userdata转换为Mat对象的引用
Mat& plot = *(static_cast<Mat*>(userdata));
// 根据鼠标事件类型执行不同的操作
switch (EVENT) {
// 鼠标左键按下时的事件处理
case EVENT_LBUTTONDOWN: {
// 更新points结构的坐标
points.x = x;
points.y = y;
// 将新的点添加到mousePoints向量中
mousePoints.push_back(points);
// 在plot图像上绘制一个白色的圆圈标记鼠标点击的位置
circle(plot, points, 4, Scalar(255, 255, 255), -1, LINE_AA);
// 更新显示图像
imshow("mouseCallback", plot);
break;
}
// 可以为其他鼠标事件添加处理代码
}
}
三、运行结果:
- 可自行更改代码,可以把输出图像进行其他处理。
drawContours(mouse_image, contours, 0, Scalar(255), -1);
mouse_image.copyTo(ROI_image);