opencv 实现 ROI 框选功能

需求描述

在图像显示界面中,鼠标左键按下并拖动,实时框选ROI,松开后得到ROI矩形框。可多次重新框选,以回车键结束框选。得到最终的ROI信息。

C++代码实现

#include"opencv2/opencv.hpp"
#include"opencv2/highgui.hpp"


// 鼠标事件数据结构体
struct onMouseData
{
public:
    cv::Mat kSrcImg;                // 原始图像
    cv::Mat kDrawImg;               // 绘图图像
    cv::Point kPointer;             // 当前鼠标坐标
    cv::Point kRectTopLeft;         // ROI左上角坐标
    cv::Point kRectBottomRight;     // ROI左下角坐标
    cv::Rect kRoi;                  // ROI矩形框信息
    cv::Scalar kLineColor;          // 矩形框线条颜色   
    int kLineWidth;                 // 矩形框线条款图
    std::string kWiddget;           // 绘图窗口名
    bool isDrawing;                 // 当前是否正在绘制ROI
    onMouseData()
    {
        kLineColor = cv::Scalar(0, 0, 255);
        kRectTopLeft = {-1, -1};
        kRectBottomRight = {-1, -1};
        kPointer = {-1, -1};
        isDrawing = false;
        kLineWidth = 1;
    }
};

// 实时绘制ROI
void drawRoi(onMouseData* kMouseData);

// 鼠标事件回调函数
void onMouseCallBack(int event, int x, int y, int flags, void* param);

// ROI选择功能函数
void selectROI(const std::string& kWiddget, const cv::Mat& kSrcImg, onMouseData& kMouseData);

int main() {
    cv::Mat kSrcImg = cv::imread("..\\..\\data\\4.1.01.tiff");
    std::string mainWidget = "ROI框选";
    cv::namedWindow(mainWidget, cv::WINDOW_KEEPRATIO);
    cv::resizeWindow(mainWidget, 256, 256);
    onMouseData kMouseData;
    selectROI(mainWidget, kSrcImg, kMouseData);
    std::cout << kMouseData.kRoi << std::endl;
    system("pause");
    cv::destroyAllWindows();
    return 0;
}

void drawRoi(onMouseData* kMouseData)
{
    if(kMouseData->isDrawing)
    {
        kMouseData->kRoi.x = kMouseData->kRectTopLeft.x;
        kMouseData->kRoi.y = kMouseData->kRectTopLeft.y;

        kMouseData->kRoi.width = kMouseData->kPointer.x - kMouseData->kRectTopLeft.x;
        kMouseData->kRoi.height = kMouseData->kPointer.y - kMouseData->kRectTopLeft.y;

        cv::rectangle(kMouseData->kDrawImg, 
                      kMouseData->kRoi, 
                      kMouseData->kLineColor, 
                      kMouseData->kLineWidth, cv::LINE_8, 0);
        cv::imshow(kMouseData->kWiddget, kMouseData->kDrawImg);
    }
}
void onMouseCallBack(int event, int x, int y, int flags, void* param)
{

    onMouseData* kMouseData = reinterpret_cast<onMouseData*>(param);
    kMouseData->kDrawImg = kMouseData->kSrcImg.clone();
    kMouseData->kPointer = {x, y};

    switch(event)
    {
        case cv::EVENT_LBUTTONDOWN:
            kMouseData->kRectTopLeft = kMouseData->kPointer;
            kMouseData->isDrawing = !kMouseData->isDrawing;
            drawRoi(kMouseData);
            break;
        case  cv::EVENT_LBUTTONUP:
            kMouseData->kRectBottomRight = kMouseData->kPointer;
            kMouseData->isDrawing = false;
            break;
        case  cv::EVENT_MOUSEMOVE:
            kMouseData->kRectBottomRight = kMouseData->kPointer;
            drawRoi(kMouseData);
            break;
        case  cv::EVENT_RBUTTONDOWN:
            kMouseData->isDrawing = false;
        default:
            break;

    }
}
void selectROI(const std::string& kWiddget, const cv::Mat& kSrcImg, onMouseData& kMouseData)
{
    kMouseData.kSrcImg = kSrcImg.clone();
    kMouseData.kWiddget = kWiddget;
    cv::imshow(kMouseData.kWiddget, kMouseData.kSrcImg);
    cv::setMouseCallback(kMouseData.kWiddget, 
                         onMouseCallBack, 
                         reinterpret_cast<void*>(&kMouseData));
    cv::waitKey();
}

结果展示

image

参考资料

posted @ 2023-05-25 01:54  GShang  阅读(282)  评论(0编辑  收藏  举报