官方文檔連結: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;
}
輸出結果: