Opencv -- 17鼠标操作与响应

2023-11-01

    函数介绍:
    1、绑定回调事件函数:

    void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);
    功能:为指定的窗口设置鼠标处理程序
    参数:
    winname – Window name (窗体的名称)
    onMouse  - 鼠标事件的回调函数。
    param 传递给回调函数的可选参数。
   
    2、鼠标事件的回调函数:MouseCallback

    typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
    
    event cv::MouseEventTypes 的常量之一。
    x     鼠标事件的x坐标。
    y     鼠标事件的y坐标。
    flags cv::MouseEventFlags 的常量之一。
    userdata 可选参数。

    cv::MouseEventFlags都有这些:
    EVENT_FLAG_ALTKEY = 32		摁住Alt
    EVENT_FLAG_CTRLKEY = 8		摁住Ctrl

    EVENT_FLAG_LBUTTON = 1		摁住左键
    EVENT_FLAG_MBUTTON = 4		摁住中键
    EVENT_FLAG_RBUTTON = 2		摁住右键
    EVENT_FLAG_SHIFTKEY = 16	摁住Shift

    EVENT_LBUTTONDBLCLK = 7		左键双击
    EVENT_LBUTTONDOWN = 1		左键击下
    EVENT_LBUTTONUP = 4			左键弹起
    EVENT_MBUTTONDBLCLK = 9		中键双击
    EVENT_MBUTTONDOWN = 3		中键击下
    EVENT_MBUTTONUP = 6			中键弹起
    EVENT_MOUSEHWHEEL = 11		滚动条向左,flags>0。向右,flags<0
    EVENT_MOUSEMOVE = 0			鼠标移动
    EVENT_MOUSEWHEEL = 10		滚动条向上,flags>0。向下,flags<0
    EVENT_RBUTTONDBLCLK = 8		中键双击
    EVENT_RBUTTONDOWN = 2		中键击下
    EVENT_RBUTTONUP = 5			中键弹起

17_opencv_mat.h 代码如下:

#pragma once

#ifndef _17_OPENCV_MAT_H
#define _17_OPENCV_MAT_H

#include <opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
public:
	void mouse_drawing_demo(Mat& image);
};

#endif

17_opencv_mat.cpp 代码如下:

#include "17_opencv_mat.h"

//借助全局变量来记录状态
Point sp(-1,-1);  //开始位置
Point ep(-1,-1);  //结束位置
static void ondraw(int event, int x, int y, int flags, void* userdata) 
{
    Mat image = *((Mat*)userdata);
    //如果鼠标左键按下
    if (event == EVENT_LBUTTONDOWN)
    {
        sp.x = x;
        sp.y = y;
        std::cout <<"start point: "<< sp << std::endl;
    }
    //如果鼠标左键弹起
    else if (event == EVENT_LBUTTONUP)
    {
        ep.x = x;
        ep.y = y;
        std::cout << "end point: " << ep << std::endl;
        int dx = ep.x - sp.x;
        int dy = ep.y - sp.y;
        if (dx > 0 && dy > 0)
        {
            Rect box(sp.x, sp.y, dx, dy);
            rectangle(image, box, Scalar(0, 0, 255), 2, LINE_8, 0);
            imshow("鼠标绘制", image);
        }
    }
}

void QuickDemo::mouse_drawing_demo(Mat &image)
{
    namedWindow("鼠标绘制", WINDOW_AUTOSIZE);

    setMouseCallback("鼠标绘制", ondraw,(void*)(&image));

    imshow("鼠标绘制",image);
}

test.cpp 代码如下:

#include <iostream>
#include "17_opencv_mat.h"

using namespace std;

int main(int argc,char** argv)
{
    //使用Mat(matrix -- 矩阵)这种类型来读取通过指定路径的图像信息并存放到变量picture中。
    //图像从本质上来说都是二维的数组(矩阵)
    Mat picture = imread("鱼头人.jpeg", IMREAD_COLOR);

    if (picture.empty())
    {
        cout << "could not Load image." << endl;
        system("pause");
        return -1;
    }
    
    // namedWindow("输入窗口",WINDOW_FREERATIO);
   
    imshow("输入窗口", picture);

    QuickDemo qd;
    qd.mouse_drawing_demo(picture);

    waitKey(0);
    destroyAllWindows();

    system("pause");
    return 0;
}

运行结果如下:
在这里插入图片描述
与此同时,
在这里插入图片描述
但是,这样的绘制有一个弊端就是无法看到绘制的过程。

我们可以这样改进:
17_opencv_mat.cpp 代码如下:

#include "17_opencv_mat.h"

//借助全局变量来记录状态
Point sp(-1,-1);  //开始位置
Point mp(-1, -1); //移动位置
static void ondraw(int event, int x, int y, int flags, void* userdata) 
{
    Mat image = *((Mat*)userdata);
    //如果鼠标左键按下
    if (event == EVENT_LBUTTONDOWN)
    {
        sp.x = x;
        sp.y = y;
        std::cout <<"start point: "<< sp << std::endl;
    }
    //如果鼠标左键弹起
    else if (event == EVENT_LBUTTONUP)
    {
        //为下一次绘制做好准备
        sp.x = -1;
        sp.y = -1;
    }
    else if (event == EVENT_MOUSEMOVE)
    {
        if (sp.x > 0 && sp.y > 0)
        {
            mp.x = x;
            mp.y = y;
            std::cout << "moving point: " << mp << std::endl;
            int dx = mp.x - sp.x;
            int dy = mp.y - sp.y;
            if (dx > 0 && dy > 0)
            {
                Rect box(sp.x, sp.y, dx, dy);
                rectangle(image, box, Scalar(0, 0, 255), 2, LINE_8, 0);
                imshow("鼠标绘制", image);
            }
        }
    }
}

void QuickDemo::mouse_drawing_demo(Mat &image)
{
    namedWindow("鼠标绘制", WINDOW_AUTOSIZE);

    setMouseCallback("鼠标绘制", ondraw,(void*)(&image));

    imshow("鼠标绘制",image);
}

改进后的效果如下:
在这里插入图片描述
这是因为它把我移动的过程中的点都进行绘制了。

那怎么解决呢?

#include "17_opencv_mat.h"

//借助全局变量来记录状态
Point sp(-1,-1);  //开始位置
Point mp(-1, -1); //移动位置
Point ep(-1,-1);  //结束位置

Mat temp;
static void ondraw(int event, int x, int y, int flags, void* userdata) 
{
    Mat image = *((Mat*)userdata);
    //如果鼠标左键按下
    if (event == EVENT_LBUTTONDOWN)
    {
        sp.x = x;
        sp.y = y;
        std::cout <<"start point: "<< sp << std::endl;
    }
    //如果鼠标左键弹起
    else if (event == EVENT_LBUTTONUP)
    {
        ep.x = x;
        ep.y = y;
        std::cout << "end point: " << ep << std::endl;
        //为下一次绘制做好准备
        sp.x = -1;
        sp.y = -1;
    }
     //如果鼠标左键被按下后移动
    else if (event == EVENT_MOUSEMOVE)
    {
        if (sp.x > 0 && sp.y > 0)
        {
            mp.x = x;
            mp.y = y;
            std::cout << "moving point: " << mp << std::endl;
            int dx = mp.x - sp.x;
            int dy = mp.y - sp.y;
            if (dx > 0 && dy > 0)
            {
                Rect box(sp.x, sp.y, dx, dy);
                //每次绘制之前就将上一次在原图上绘制了矩形的那个图給覆盖成原图,
                //从而只保留最后一次绘制。
                temp.copyTo(image);
                rectangle(image, box, Scalar(0, 0, 255), 2, LINE_8, 0);
                imshow("鼠标绘制", image);
            }
        }
    }
}

void QuickDemo::mouse_drawing_demo(Mat &image)
{
    namedWindow("鼠标绘制", WINDOW_AUTOSIZE);

    setMouseCallback("鼠标绘制", ondraw,(void*)(&image));

    imshow("鼠标绘制",image);

    temp = image.clone();
}

最终运行结果如下:

在这里插入图片描述
现在,我们获得了矩形的起始坐标和结束坐标,我们就可以将矩形部分(ROI区域)的图像给提取出来,应该怎么做呢?

...
temp.copyTo(image); 

imshow("ROI区域", image(box));//只需要添加这句代码

rectangle(image, box, Scalar(0, 0, 255), 2, LINE_8, 0);
...

运行代码如下:
在这里插入图片描述
需要注意的是,最后鼠标的结束坐标不能在窗口外,否则会报错。

因此需要进行改进,改进如下:

#include "17_opencv_mat.h"

//借助全局变量来记录状态
Point sp(-1,-1);  //开始位置
Point mp(-1, -1); //移动位置
Point ep(-1,-1);  //结束位置

Mat temp;
static void ondraw(int event, int x, int y, int flags, void* userdata) 
{
    Mat image = *((Mat*)userdata);

    int w = image.cols; // 列
    int h = image.rows; // 行

    //如果鼠标左键按下
    if (event == EVENT_LBUTTONDOWN)
    {
        sp.x = x;
        sp.y = y;
        std::cout <<"start point: "<< sp << std::endl;
    }
    //如果鼠标左键弹起
    else if (event == EVENT_LBUTTONUP)
    {
        ep.x = x;
        ep.y = y;

        if (ep.x > w || ep.y > h)
        {
            std::cout<< "End Beyond the border" << std::endl;

            //为下一次绘制做好准备
            sp.x = -1;
            sp.y = -1;
        }
        else
        { 
            std::cout << "end point: " << ep << std::endl;
            //为下一次绘制做好准备
            sp.x = -1;
            sp.y = -1;
        }
    }
    else if (event == EVENT_MOUSEMOVE)
    {
        if (sp.x > 0 && sp.y > 0)
        {
            mp.x = x;
            mp.y = y;
            if (mp.x > w || mp.y > h)
            {
                std::cout << "Move Beyond the border" << std::endl;

                int dx = w - sp.x;
                int dy = h - sp.y;
                if (dx > 0 && dy > 0)
                {
                    Rect box(sp.x, sp.y, dx, dy);
                    //每次绘制之前就将上一次在原图上绘制了矩形的那个图給覆盖成原图,
                    //从而只保留最后一次绘制。
                    temp.copyTo(image);
                    imshow("ROI区域", image(box));
                    rectangle(image, box, Scalar(0, 0, 255), 2, LINE_8, 0);
                    imshow("鼠标绘制", image);
                }
            }
            else
            { 
                int dx = mp.x - sp.x;
                int dy = mp.y - sp.y;
                if (dx > 0 && dy > 0)
                {
                    Rect box(sp.x, sp.y, dx, dy);
                    //每次绘制之前就将上一次在原图上绘制了矩形的那个图給覆盖成原图,
                    //从而只保留最后一次绘制。
                    temp.copyTo(image);
                    imshow("ROI区域", image(box));
                    rectangle(image, box, Scalar(0, 0, 255), 2, LINE_8, 0);
                    imshow("鼠标绘制", image);
                }
            }
        }
    }
}

void QuickDemo::mouse_drawing_demo(Mat &image)
{
    namedWindow("鼠标绘制", WINDOW_AUTOSIZE);

    setMouseCallback("鼠标绘制", ondraw,(void*)(&image));

    imshow("鼠标绘制",image);

    temp = image.clone();
}

效果如下:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Opencv -- 17鼠标操作与响应 的相关文章

  • OpenCV Mat 和 Leptonica Pix 之间的转换

    我需要在 C 中在 OpenCV Mat 图像和 Leptonica Pix 图像格式之间进行转换 这用于 8 位灰度图像的二值化 我发现发现了 ikaliga的回答 https stackoverflow com a 25929320 2
  • YOLOv8获取预测边界框

    我想将 OpenCV 与 YOLOv8 集成ultralytics 所以我想从模型预测中获取边界框坐标 我该怎么做呢 from ultralytics import YOLO import cv2 model YOLO yolov8n pt
  • 在 Visual Studio C++ 2008 中包含 dll

    有没有办法将 dll 包含在项目中 这样我就不必在编译后将这些 dll 与可执行文件放在同一文件夹中 这样我就可以用它们编译我的项目 这是否有可能 如果是 有人可以指导我 我的项目是一个 opencv 项目 有很多 dll 我必须包含在文件
  • VideoCapture.read() 返回过去的图像

    我在跑python3 6 with openCV on the Raspberry pi OS is Raspbian 代码的大致结构如下 The image以时间间隔 3 5 分钟 捕获 被捕获image在函数中处理并返回度量 精度的种类
  • opencv水印周围的轮廓

    我想在图像中的水印周围画一个框 我已经提取了水印并找到了轮廓 但是 不会在水印周围绘制轮廓 轮廓是在我的整个图像上绘制的 请帮我提供正确的代码 轮廓坐标的输出为 array 0 0 0 634 450 634 450 0 dtype int
  • 从扫描文档中提取行表 opencv python

    我想从扫描的表中提取信息并将其存储为 csv 现在我的表提取算法执行以下步骤 应用倾斜校正 应用高斯滤波器进行去噪 使用 Otsu 阈值进行二值化 进行形态学开局 Canny 边缘检测 进行霍夫变换以获得表格行 去除重复行 10像素范围内相
  • 如何检测斑点并将其裁剪成 png 文件?

    我一直在开发一个网络应用程序 我陷入了一个有问题的问题 我会尝试解释我想要做什么 在这里您看到第一个大图像 其中有绿色形状 我想要做的是将这些形状裁剪成不同的 png 文件 并使它们的背景透明 就像大图像下面的示例裁剪图像一样 第一张图像将
  • 在骨架图像中查找线 OpenCV python

    我有以下图片 我想找到一些线来进行一些计算 平均长度等 我尝试使用HoughLinesP 但它找不到线 我能怎么做 这是我的代码 sk skeleton mask rows cols sk shape imgOut np zeros row
  • opencv中如何去除二值图像噪声?

    将图像转换为二值图像 黑白 后如果有任何噪音怎么办 我消除了那些不需要的噪音 您可以看到下图的黑色区域内有一些白噪声 我该如何去除噪声 使用opencv http img857 imageshack us img857 999 blackn
  • 提取二值图像中的最中心区域

    我正在处理二进制图像 之前使用此代码来查找二进制图像中的最大区域 Use the hue value to convert to binary thresh 20 thresh thresh img cv2 threshold h thre
  • 在Python中从整个图像中检测表格部分

    我有一张尺寸为 3500x5000 的图像 现在我只想检测整个图像中的表格部分 如果不能直接进行 OCR 处理 则对其进行裁剪和旋转 经过所有搜索后 我想到了使用裁剪图像中的每个单元格的想法https medium com coinmonk
  • OpenCV Python 和 SIFT 功能

    我知道有很多关于Python and OpenCV但我没有找到有关这个特殊主题的帮助 我想提取SIFT关键点来自 python OpenCV 中的图像 我最近安装了 OpenCV 2 3 可以访问 SURF 和 MSER 但不能访问 SIF
  • 将图像加载到现有 Mat 中

    有没有办法将图像加载到现有的 Mat 中 如果没有 有没有办法控制 OpenCV 在调用 cv imread 时分配内存的位置 我只是为您的类创建一个构造函数 该构造函数接受 imread 的输入参数并将图像直接加载 并分配 到您的类中 所
  • 在 Tensorflow-lite Android 中将位图转换为 ByteBuffer(浮点)

    在用于图像分类的tensorflow lite android演示代码中 图像首先转换为ByteBuffer格式以获得更好的性能 这种从位图到浮点格式的转换以及随后到字节缓冲区的转换似乎是一个昂贵的操作 循环 按位运算符 float mem
  • 在 virtualenvwrapper 中激活环境

    我安装了virtualenv and virtualenvwrapper用这个命令我创建了一个环境 mkvirtualenv cv 它有效 创建后我就处于新环境中 现在我重新启动了我的电脑 我想activate又是那个环境 但是怎么样 我使
  • 从基本矩阵中查找单应矩阵

    我正在尝试计算单应性矩阵H给定一组对应关系和基本矩阵F 根据对极几何原理 我知道这可以通过对极线和对极线的叉积来完成F from 极点几何 http www cs unc edu marc tutorial node44 html e ij
  • OpenCV 中的 Canny 可以同时处理灰度图像和彩色图像吗?

    我有一些关于Canny 边缘检测器 in OpenCV 这是我尝试过的代码 def auto canny image sigma 0 33 v np median image lower int max 0 1 0 sigma v uppe
  • 使用 Brew 安装 OpenCV 永远不会完成

    所以我尝试使用 Homebrew 安装 opencv 但它不起作用 我用了brew tap homebrew science进而brew install opencv发生的情况是 gt Installing opencv from home
  • 使用 OpenCV 描述符与 findFundamentalMat 匹配

    我之前发布了有关同一程序的问题 但没有收到答案 我已经纠正了当时遇到的问题 但又面临新的问题 基本上 我使用未校准的方法自动校正立体图像对的旋转和平移 我使用 SURF 等特征检测算法来查找两个图像 左右立体图像对 中的点 然后再次使用 S
  • OpenCV InRange 参数

    我在 Android 上使用 OpenCV 来实时查找特定颜色的圆圈 我的第一步是仅保留与我正在寻找的定义颜色相对应的像素 在本例中为红色或绿色 示例图像 https i stack imgur com CIozU jpg 为此 我正在使用

随机推荐