12.OpenCV鼠标操作

OpenCV鼠标操作

  在计算机视觉和图像处理的开发中,我们经常需要与图像窗口进行交互,例如选取目标区域、标注图像或者动态绘图。OpenCV 提供了基本的鼠标操作接口,使得开发者可以捕获鼠标点击、移动、拖拽等事件,从而实现丰富的交互功能。本文将介绍 OpenCV 鼠标操作的基本原理、如何设置鼠标事件回调函数以及结合示例代码.

鼠标常用场景

  • 图像标注:通过鼠标选取区域进行目标标注或区域分割。
  • 交互式绘图:例如绘制直线、曲线、矩形或多边形,用于数据标注和调试。
  • 图像裁剪:实现用户自定义裁剪区域,快速获得感兴趣区域。
  • 增强交互体验:开发交互式图像编辑工具或可视化应用时,通过鼠标操作实现实时反馈。

1. 鼠标事件简介

OpenCV 通过 cv::setMouseCallback 函数为窗口绑定鼠标事件回调函数,该函数会在鼠标发生特定事件时被自动调用。常见的鼠标事件包括:

  • EVENT_LBUTTONDOWN:鼠标左键按下
  • EVENT_LBUTTONUP:鼠标左键释放
  • EVENT_RBUTTONDOWN:鼠标右键按下
  • EVENT_RBUTTONUP:鼠标右键释放
  • EVENT_MBUTTONDOWN:鼠标中键按下
  • EVENT_MOUSEMOVE:鼠标移动
  • EVENT_LBUTTONDBLCLK:鼠标左键双击

每个事件都有不同的用途,例如在图像上拖拽绘制矩形、捕获点击位置或者进行目标追踪,都可以依靠这些事件来实现交互。

2. 回调函数实现

在设置鼠标回调函数时,我们需要定义一个特定格式的函数,该函数会在鼠标事件触发时被调用。函数原型如下:

void onMouse(int event, int x, int y, int flags, void* userdata);
  • event:表示鼠标事件类型,如 EVENT_LBUTTONDOWN
  • x, y:鼠标事件发生时的图像坐标
  • flags:表示鼠标事件的附加信息(如 Ctrl、Shift 键状态等)
  • userdata:用户自定义数据,可以传递需要在回调中使用的其他信息

在回调函数中,我们可以根据事件类型实现不同的操作,例如在鼠标左键按下时记录起点,移动时动态显示绘图效果,左键释放时完成绘制等。

3. 示例代码:绘制矩形

以下示例代码演示了如何利用鼠标事件在图像窗口中动态绘制矩形。程序在鼠标左键按下时记录起始点,拖拽过程中显示动态矩形,左键释放后完成绘制。

#include "stdio.h"
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
// 全局变量,用于存储绘制状态和起点坐标
bool drawing = false;
Point startPoint;
Mat image, tempImage;
/**
 * \brief 鼠标回调.
 * 
 * \param event:表示鼠标事件类型,如 EVENT_LBUTTONDOWN
 * \param x:鼠标事件发生时的图像坐标
 * \param y:鼠标事件发生时的图像坐标
 * \param flags:表示鼠标事件的附加信息(如 Ctrl、Shift 键状态等)
 * \param userdata:用户自定义数据,可以传递需要在回调中使用的其他信息
 */
void onMouse(int event, int x, int y, int flags, void* userdata)
{
    if (event == EVENT_LBUTTONDOWN) {
        drawing = true;
        startPoint = Point(x, y);
        tempImage = image.clone();  // 保存当前图像状态
    }
    else if (event == EVENT_MOUSEMOVE && drawing) {
        // 拖拽时动态绘制矩形
        image = tempImage.clone();
        rectangle(image, startPoint, Point(x, y), Scalar(0, 255, 0), 2);
        imshow("Mouse Drawing", image);
    }
    else if (event == EVENT_LBUTTONUP && drawing) {
        drawing = false;
        Point endPoint(x, y);
        // 保证左上和右下坐标正确
        int x_min = min(startPoint.x, endPoint.x);
        int y_min = min(startPoint.y, endPoint.y);
        int x_max = max(startPoint.x, endPoint.x);
        int y_max = max(startPoint.y, endPoint.y);
        int rect_width = x_max - x_min;
        int rect_height = y_max - y_min;

        // 绘制最终的矩形
        rectangle(image, Point(x_min, y_min), Point(x_max, y_max), Scalar(0, 255, 0), 2);

        // 生成矩形信息文字,例如:"x: 50 y: 50 w: 200 h: 150"
        string info = "x:" + to_string(x_min) + " y:" + to_string(y_min) +
            " w:" + to_string(rect_width) + " h:" + to_string(rect_height);

        // 设置文字背景区域:在矩形下方显示
        int margin = 5;
        int textRectX = x_min;
        int textRectY = y_max + margin;
        int textRectWidth = rect_width;
        int textRectHeight = 30;  // 固定高度

        // 若超出图像下边界,则调整位置
        if (textRectY + textRectHeight > image.rows) {
            textRectY = image.rows - textRectHeight;
        }

        // 绘制填充背景(黑色)
        rectangle(image, Point(textRectX, textRectY),
            Point(textRectX + textRectWidth, textRectY + textRectHeight),
            Scalar(0, 0, 0), FILLED);

        // 设置文字样式
        int fontFace = FONT_HERSHEY_SIMPLEX;
        double fontScale = 0.5;
        int thickness = 1;
        int baseline = 0;
        Size textSize = getTextSize(info, fontFace, fontScale, thickness, &baseline);

        // 计算文字在背景矩形中的居中位置
        Point textOrg(textRectX + (textRectWidth - textSize.width) / 2,
            textRectY + (textRectHeight + textSize.height) / 2);

        // 在背景上绘制白色文字
        putText(image, info, textOrg, fontFace, fontScale, Scalar(255, 255, 255), thickness);

        imshow("Mouse Drawing", image);
    }
}

int main()
{
    image = imread("E:/image/lena.png");

	namedWindow("Mouse Drawing", WINDOW_AUTOSIZE);
	//设置鼠标操作回调函数
	setMouseCallback("Mouse Drawing", onMouse, NULL);

	imshow("Mouse Drawing", image);
	cout << "请在图像窗口中按住鼠标左键拖拽绘制矩形..." << endl;
	waitKey();
	cv::destroyAllWindows();
	return 0;
}

3.1代码解析

  1. 全局变量

    • drawing 用于记录是否正在绘图。
    • startPoint 保存鼠标左键按下时的坐标。
    • image 为当前显示图像,tempImage 用于在绘图过程中保存原图状态。
  2. onMouse 回调函数

    根据鼠标事件类型分别处理:

    • 按下:开始绘图并记录起点。
    • 移动:实时更新绘制效果,显示动态矩形。
    • 释放:最终绘制矩形并结束操作。
  3. 主函数

    创建窗口、绑定回调函数并显示初始图像,等待用户操作。

  4. 最终效果如下图
    鼠标绘制矩形

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值