官方文档链接:https://dovyski.github.io/cvui/advanced-mouse/
Mouse
cvui 拥有自己的鼠标 API 可以追踪鼠标点击和光标位置。与鼠标相关的所有内容都可以从 cvui::mouse() 中访问到。以下部分将详细介绍所有可用的鼠标信息。
光标位置(Cursor position)
用户可以通过调用 cvui::mouse() 随时查询鼠标光标的位置,它返回一个 cv::Point():
示例:
// Save the mouse cursor to a point object
cv::Point cursor = cvui::mouse();
std::cout << "x: " << cursor.x << " y: " << cursor.y << std::endl;
// or access the position directly
std::cout << "x: " << cvui::mouse().x << " y: " << cvui::mouse().y << std::endl;
对 cvui::mouse() 的调用始终返回当前信息,因此用户不需要监听鼠标事件。只要调用 cvui::mouse(),就可以得到鼠标光标的最新位置。
检测事件 (Detect events)
用户可以通过调用 cvui::mouse(int) 来查询鼠标的状态,例如单击,其函数声明如下:
参数 theQuery 是指定查询的整数。可用查询包括:
- cvui::DOWN:查询是否按下了任何鼠标按键。cvui::mouse() 只对单个帧(鼠标按键按下的帧)返回 true。
- cvui::UP:查询是否由鼠标按键被释放。cvui::mouse()只对单个帧(鼠标按键向上的帧)返回 true。
- cvui::CLICK:查询是否单击了任何鼠标按键(按下然后释放,不管中间有多少帧)。cvui::mouse() 只对单个帧返回 true。
- cvui::IS_DOWN:查询当前是否按下了任何鼠标按键。只要按下鼠标按键,cvui::mouse() 返回 true。
重要:对 cvui::mouse(int) 的调用将查询所有鼠标按键,因此如果按下任何鼠标按键,则调用 cvui::mouse(cvui::DOWN) 将返回 true。
在下面的例子中,当按下任意鼠标按键,将会显示信息:
if(cvui::mouse(cvui::DOWN))
{
std::cout << "Any mouse button just went down." << std::endl;
}
在下面的例子中,当点击鼠标按键,将会显示信息(按下然后释放):
if(cvui::mouse(cvui::CLICK))
{
std::cout << "A mouse click just happened." << std::endl;
}
逐个检查鼠标按钮 (Check mouse buttons individually)
用户可以查询特定的鼠标按键的状态,例如对鼠标左键上的单击做出反应。
可以通过 cvui::mouse(int, int) 查询特定的鼠标按键,其函数声明为:
参数 theButton 允许用户指定要查询的鼠标按钮。可用的按钮有 cvui::LEFT_BUTTON,cvui::MIDDLE_BUTTON,cvui::RIGHT_BUTTON。
函数 cvui::mouse(int theButton, int theQuery) 的工作方式与 cvui::mouse(int theQuery) 完全相同,唯一的区别是查询的目标是特定的按键,而不是所有的按键。
下面是按下鼠标左键时打印信息的示例:
if(cvui::mouse(cvui::LEFT_BUTTON, cvui::DOWN))
{
std::cout << "Left mouse button just went down." << std::endl;
}
输出结果:

点击窗口任意位置即可触发输出事件。
示例一
完整代码:
#define CVUI_IMPLEMENTATION
#define CVUI_DISABLE_COMPILATION_NOTICES
#include "cvui.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define WINDOW_NAME "CVUI Test"
int main(int argc, char** argv)
{
cvui::init(WINDOW_NAME);
cv::Mat frame = cv::Mat(cv::Size(800, 600), CV_8UC3);
cv::Rect rectangle(0, 0, 0, 0);
while (true)
{
frame = cv::Scalar(100, 100, 100);
cvui::text(frame, 10, 30, "Click (any) mouse button and drag the pointer around to select an area.");
cvui::printf(frame, 10, 50, "Mouse pointer is at (%d, %d)", cvui::mouse().x, cvui::mouse().y);
if (cvui::mouse(cvui::DOWN))
{
rectangle.x = cvui::mouse().x;
rectangle.y = cvui::mouse().y;
}
if (cvui::mouse(cvui::IS_DOWN))
{
rectangle.width = cvui::mouse().x - rectangle.x;
rectangle.height = cvui::mouse().y - rectangle.y;
cvui::printf(frame, rectangle.x + 5, rectangle.y + 5, 0.3, 0xffffff, "(%d, %d)", rectangle.x, rectangle.y);
cvui::printf(frame, cvui::mouse().x + 5, cvui::mouse().y + 5, 0.3, 0xffffff, "w:%d, h:%d", rectangle.width, rectangle.height);
}
if (cvui::mouse(cvui::UP))
{
rectangle.x = 0;
rectangle.y = 0;
rectangle.width = 0;
rectangle.height = 0;
}
if (cvui::mouse(cvui::CLICK))
cvui::text(frame, 10, 70, "Mouse was clicked!");
//cvui::rect(frame, rectangle.x, rectangle.y, rectangle.width, rectangle.height, 0xff0000);
cvui::rect(frame, rectangle.x, rectangle.y, rectangle.width, rectangle.height, 0xff0000, 0xffffffff);
cvui::imshow(WINDOW_NAME, frame);
if (cv::waitKey(20) == 27)
break;
}
return 0;
}
输出结果:
此程序运行时,按下鼠标会在 frame 中的对应位置显示坐标,同时拖动鼠标会在 frame 的对应区域处形成一个矩形框,矩形框的右下角将显示矩形框的宽度和高度。
值得注意的是如下代码:
if (cvui::mouse(cvui::DOWN))
{
rectangle.x = cvui::mouse().x;
rectangle.y = cvui::mouse().y;
}
if (cvui::mouse(cvui::IS_DOWN))
{
rectangle.width = cvui::mouse().x - rectangle.x;
rectangle.height = cvui::mouse().y - rectangle.y;
cvui::printf(frame, rectangle.x + 5, rectangle.y + 5, 0.3, 0xffffff, "(%d, %d)", rectangle.x, rectangle.y);
cvui::printf(frame, cvui::mouse().x + 5, cvui::mouse().y + 5, 0.3, 0xffffff, "w:%d, h:%d", rectangle.width, rectangle.height);
}
cvui::DOWN 可以用来表示鼠标按下的这个动作,而 cvui::IS_DOWN 可以用来表示鼠标一直处于按下的状态。
示例二
完整代码:
#define CVUI_IMPLEMENTATION
#define CVUI_DISABLE_COMPILATION_NOTICES
#include "cvui.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define WINDOW_NAME "Mouse - ROI interaction"
#define ROI_WINDOW "ROI"
int main(int argc, char** argv)
{
cvui::init(WINDOW_NAME);
cv::Mat lena = cv::imread("lena.jpg");
cv::Mat frame = lena.clone();
cv::Point anchor;
cv::Rect roi(0, 0, 0, 0);
bool working = false;
while (true)
{
lena.copyTo(frame);
cvui::text(frame, 10, 10, "Click (any) mouse button and drag the pointer around to select a ROI.");
if (cvui::mouse(cvui::DOWN))
{
anchor.x = cvui::mouse().x;
anchor.y = cvui::mouse().y;
working = true;
}
if (cvui::mouse(cvui::IS_DOWN))
{
int width = cvui::mouse().x - anchor.x;
int height = cvui::mouse().y - anchor.y;
roi.x = width < 0 ? anchor.x + width : anchor.x;
roi.y = height < 0 ? anchor.y + height : anchor.y;
roi.width = std::abs(width);
roi.height = std::abs(height);
cvui::printf(frame, roi.x + 5, roi.y + 5, 0.3, 0xffffff, "(%d, %d)", roi.x, roi.y);
cvui::printf(frame, cvui::mouse().x + 5, cvui::mouse().y + 5, 0.3, 0xffffff, "w:%d, h:%d", roi.width, roi.height);
}
if (cvui::mouse(cvui::UP))
working = false;
roi.x = roi.x < 0 ? 0 : roi.x;
roi.y = roi.y < 0 ? 0 : roi.y;
roi.width = roi.x + roi.width > lena.cols ? roi.width + lena.cols - (roi.x + roi.width) : roi.width;
roi.height = roi.y + roi.height > lena.rows ? roi.height + lena.rows - (roi.y + roi.height) : roi.height;
cvui::rect(frame, roi.x, roi.y, roi.width, roi.height, 0xff0000);
cvui::imshow(WINDOW_NAME, frame);
if (roi.area() > 0 && !working)
cv::imshow(ROI_WINDOW, lena(roi));
if (cv::waitKey(20) == 27)
break;
}
return 0;
}
输出图像:
示例三
完整代码:
#define CVUI_IMPLEMENTATION
#define CVUI_DISABLE_COMPILATION_NOTICES
#include "cvui.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define WINDOW_NAME "Mouse complex buttons - ROI interaction"
int main(int argc, char** argv)
{
cv::Mat lena = cv::imread("lena.jpg");
cv::Mat frame = lena.clone();
cv::Point anchors[3];
cv::Rect rois[3];
unsigned int colors[] = { 0xff0000, 0x00ff00, 0x0000ff };
cvui::init(WINDOW_NAME);
while (true) {
lena.copyTo(frame);
cvui::text(frame, 10, 10, "Click (any) mouse button then drag the pointer around to select a ROI.");
cvui::text(frame, 10, 25, "Use different mouse buttons (right, middle and left) to select different ROIs.");
for (int button = cvui::LEFT_BUTTON; button <= cvui::RIGHT_BUTTON; button++)
{
cv::Point& anchor = anchors[button];
cv::Rect& roi = rois[button];
unsigned int color = colors[button];
if (cvui::mouse(button, cvui::DOWN))
{
anchor.x = cvui::mouse().x;
anchor.y = cvui::mouse().y;
}
if (cvui::mouse(button, cvui::IS_DOWN))
{
int width = cvui::mouse().x - anchor.x;
int height = cvui::mouse().y - anchor.y;
roi.x = width < 0 ? anchor.x + width : anchor.x;
roi.y = height < 0 ? anchor.y + height : anchor.y;
roi.width = std::abs(width);
roi.height = std::abs(height);
cvui::printf(frame, roi.x + 5, roi.y + 5, 0.3, color, "(%d, %d)", roi.x, roi.y);
cvui::printf(frame, cvui::mouse().x + 5, cvui::mouse().y + 5, 0.3, color, "w:%d, h:%d", roi.width, roi.height);
}
roi.x = roi.x < 0 ? 0 : roi.x;
roi.y = roi.y < 0 ? 0 : roi.y;
roi.width = roi.x + roi.width > lena.cols ? roi.width + lena.cols - (roi.x + roi.width) : roi.width;
roi.height = roi.y + roi.height > lena.rows ? roi.height + lena.rows - (roi.y + roi.height) : roi.height;
if (roi.area() > 0)
{
cvui::rect(frame, roi.x, roi.y, roi.width, roi.height, color);
cvui::printf(frame, roi.x + 5, roi.y - 10, 0.3, color, "ROI %d", button);
cv::imshow("ROI button " + std::to_string(button), lena(roi));
}
}
cvui::update();
cv::imshow(WINDOW_NAME, frame);
if (cv::waitKey(20) == 27) {
break;
}
}
return 0;
}
输出结果: