opencv 实现 ROI 框选功能

Posted GShang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv 实现 ROI 框选功能相关的知识,希望对你有一定的参考价值。

在图像显示界面中,鼠标左键按下并拖动,实时框选ROI,松开后得到ROI矩形框。可多次重新框选,以回车键结束框选。得到最终的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();

结果展示

参考资料

OpenCV学习笔记15-目标跟踪算法介绍及实战

文章目录

1. 目标追踪介绍

知乎上有篇文章对目标追踪介绍的非常清晰. 目标追踪综述

2. OpenCV目标追踪算法介绍

OpenCV上有八种不同的目标追踪算法.

BOOSTING Tracker:和Haar cascades(AdaBoost)背后所用的机器学习算法相同,但是距其诞生已有十多年了。这一追踪器速度较慢,并且表现不好。(最低支持OpenCV 3.0.0)

MIL Tracker:比上一个追踪器更精确,但是失败率比较高。(最低支持OpenCV 3.0.0)

KCF Tracker:比BOOSTING和MIL都快,但是在有遮挡的情况下表现不佳。(最低支持OpenCV 3.1.0)

CSRT Tracker:比KCF稍精确,但速度不佳。(最低支持OpenCV 3.4.2)

MedianFlow Tracker:出色的跟踪故障报告。当运动是可预测的并且没有遮挡时,效果非常好,但是对于快速跳动或快速移动的物体,模型会失效。(最低支持OpenCV 3.0.0)

TLD Tracker:在多帧遮挡下效果最好。但是TLD的误报非常多,所以不推荐。(最低支持OpenCV 3.0.0)

MOSSE Tracker:速度真心快,但是不如CSRT和KCF的准确率那么高,如果追求速度选它准没错。(最低支持OpenCV 3.4.1)

GOTURN Tracker:这是OpenCV中唯一一深度学习为基础的目标检测器。它需要额外的模型才能运行。(最低支持OpenCV 3.2.0)

3. 目标追踪过程

3.1 定义目标追踪算法

定义不同的目标追踪算法(不含深度学习):

# 定义OpenCV中的七种目标追踪算法
OPENCV_OBJECT_TRACKERS = 
    'boosting': cv2.legacy.TrackerBoosting_create,
    'csrt': cv2.legacy.TrackerCSRT_create,
    'kcf': cv2.legacy.TrackerKCF_create,
    'mil': cv2.legacy.TrackerMIL_create,
    'tld': cv2.legacy.TrackerTLD_create,
    'medianflow': cv2.legacy.TrackerMedianFlow_create,
    'mosse': cv2.legacy.TrackerMOSSE_create  

3.2 初始化追踪器集合

通过MultiTracker_create初始化追踪器集合:

trackers = cv2.MultiTracker_create()

3.3 更新目标追踪器

根据trackers.update更新目标追踪器:

  • trackers.update(image)
    • image:传入的图像
    • 返回两个参数,一个是是否追踪成功,另一个是追踪到的ROI框
success, boxes = trackers.update(frame)

3.4 绘制目标区域

根据trackers.update返回的区域集boxes,绘制不同的目标区域。

box是一个浮点型的ndarray,绘图时需要转成int型

# 绘制追踪到的矩形区域
for box in boxes:
    (x, y, w, h) = [int(v) for v in box]
    cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

3.5 对感兴趣的区域进行框截取ROI:

  • cv2.selectROI(windowName, img[, showCrosshair[, fromCenter]])
    • windowName:选择的区域被显示在的窗口的名字
    • img:要在什么图像上进行ROI
    • showCrosshair:是否在矩形框里画十字线,默认为True。
    • fromCenter:是否在矩形框里画十字线,默认为False。
    • 返回的是一个列表:[min_x,min_y,w,h]:
      • min_x为矩形框中最小的x值,左上角
      • min_y为矩形框中最小的y值,左上角
      • w为这个矩形框的宽
      • h为这个矩形框的高
    • 选好区域后,按空格或者Enter完成选择;换区域的时候直接通过鼠标重新选择即可
3.5.1 框选ROI区域:
roi = cv2.selectROI('frame', frame, showCrosshair=xxx, fromCenter=xxx)

完整展示:

import cv2

cap = cv2.VideoCapture('./videos/soccer_01.mp4')

while True:
    flag, frame = cap.read()
    if frame is None:
        break
    cv2.imshow('frame', frame)    
    key = cv2.waitKey(100)  
    if key == ord('s'):
        # 框选ROI区域
        roi = cv2.selectROI('frame', frame, showCrosshair=True, fromCenter=False)
        print(roi)
        # 退出,27为Esc的AscII的值
    elif key == 27:
        break
cap.release()
cv2.destroyAllWindows()
3.5.2 截取ROI:
roi_img = img[int(roi[1]):int(roi[1]+roi[3]), int(roi[0]):int(roi[0]+roi[2])]  # 先高后宽

完整展示:

import cv2

cap = cv2.VideoCapture('./videos/soccer_01.mp4')

while True:
    flag, frame = cap.read()
    if frame is None:
        break
    cv2.imshow('frame', frame)    
    key = cv2.waitKey(100)  
    if key == ord('s'):
        # 框选ROI区域
        roi = cv2.selectROI('frame', frame, showCrosshair=True, fromCenter=False)
        # 截取ROI区域
        roi_img = frame[int(roi[1]):int(roi[1]+roi[3]), int(roi[0]):int(roi[0]+roi[2])]
        cv2.imshow('roi_img', roi_img)
    elif key == 27:
        break
cap.release()
cv2.destroyAllWindows()

3.7 根据需要创建新的追踪目标

3.7.1 创建一个实际的目标追踪器:
tracker = OPENCV_OBJECT_TRACKERS['xxx']()
3.7.2 将选择好的目标添加到追踪器上:
  • trackers.add(newTracker, image, boundingBox)
    • newTracker:追踪器
    • image:传入的图像
    • boundingBox:ROI区域

4. 目标跟踪算法的使用

OpenCV目标跟踪算法的使用大概可以分为以下几个步骤:

  1. 创建MultiTracker对象.
  2. 读取视频或摄像头数据.
  3. 框选ROI区域
  4. 给MultiTracker对象添加实际的追踪算法.
  5. 对每一帧进行进行目标追踪.

完整代码:

import cv2

# MultiTracker_create以及一些其他的目标追踪算法在opencv4.5以后换了地方. 
# cv2.legacy.MultiTracker_create

# 定义OpenCV中的七种目标追踪算法
OPENCV_OBJECT_TRACKERS = 
    'boosting': cv2.legacy.TrackerBoosting_create,
    'csrt': cv2.legacy.TrackerCSRT_create,
    'kcf': cv2.legacy.TrackerKCF_create,
    'mil': cv2.legacy.TrackerMIL_create,
    'tld': cv2.legacy.TrackerTLD_create,
    'medianflow': cv2.legacy.TrackerMedianFlow_create,
    'mosse': cv2.legacy.TrackerMOSSE_create  

# 初始化追踪器集合
trackers = cv2.legacy.MultiTracker_create()
# 读取视频
cap = cv2.VideoCapture('./videos/soccer_01.mp4')

while True:
    flag, frame = cap.read()
    if frame is None:
        break
    # 更新追踪器,追踪目标
    success, boxes = trackers.update(frame)
    # 绘制追踪到的矩形区域
    for box in boxes:
        # box是个浮点型ndarray, 画图需要整型
        (x, y, w, h) = [int(v) for v in box]
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
        
    cv2.imshow('frame', frame)
    
    key = cv2.waitKey(30)
    if key == ord('s'):
        # 框选ROI区域
        roi = cv2.selectROI('frame', frame, showCrosshair=True, fromCenter=False)
#         print(roi)
        # 创建一个实际的目标追踪器
        tracker = OPENCV_OBJECT_TRACKERS['csrt']()
        trackers.add(tracker, frame, roi)
    elif key == 27:
        break
        
cap.release()
cv2.destroyAllWindows()

结果展示:



附OpenCV目录:OpenCV总目录学习笔记

智科专业小白,写博文不容易,如果喜欢的话可以点个赞哦!

以上是关于opencv 实现 ROI 框选功能的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV学习-不规则ROI的提取

OpenCV高手勿入! 半小时学会基本操作 8 ROI & 泛洪

OpenCV-C++选择提取感兴趣区域(ROI区域)附用鼠标选取ROI区域的代码

使用Python,OpenCV截取图片ROI

OpenCV之图像ROI与ROI操作

opencv-鼠标框选矩形区域并输出尺寸