opencv学习笔记25-opencv鼠标选择感兴趣区域(ROI)

一、函数:

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;
        }
        // 可以为其他鼠标事件添加处理代码
    }
}

三、运行结果:

b5915de3253b4cc78fc88ef9e591eda7.png

759bbfff6c9f439ea6ecd966d91ee523.png

  • 可自行更改代码,可以把输出图像进行其他处理。

20230724024159.png?origin_url=data%3Aimage%2Fgif%3Bbase64%2CR0lGODlhAQABAPABAP%2F%2F%2FwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D&pos_id=uqQiL8R8

drawContours(mouse_image, contours, 0, Scalar(255), -1);
mouse_image.copyTo(ROI_image);

3f90772880ca40809a819c32050af916.png

 

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值