今天学习了下HighGUI的鼠标事件,书上的例程完成了随机颜色的矩形框的绘制,代码如下:
// 鼠标测试:绘制彩色矩形框
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
#define WINDOW_NAME "【程序窗口】"
//--------------------【全局函数声明部分】---------------------
// 描述:全局函数的声明
//----------------------------------------------------------
//鼠标回调函数
void on_MouseHandle(int event, int x, int y, int flags, void * param);
void DrawRactangle(Mat & img, Rect box);
//---------------------【全局变量声明部分】--------------------
// 描述:全局变量的声明
//----------------------------------------------------------
Rect g_rectangle;//矩形框变量
bool g_bDrawingBox = false;//是否进行绘制
RNG g_rng(12345);
//-------------------------【主函数】------------------------
// 描述:主函数
//----------------------------------------------------------
int main(int argc, char ** argv)
{
//准备参数
g_rectangle = Rect(-1, -1, 0, 0);
Mat srcImage(600, 800, CV_8UC3), tempImage;
srcImage.copyTo(tempImage);
srcImage = Scalar::all(0);
// 设置鼠标操作回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void *)&srcImage);
// 程序主循环,当进行绘制的标识符为真的时候进行绘制
while (1)
{
srcImage.copyTo(tempImage); // 复制源图到临时变量
if (g_bDrawingBox)
{
DrawRactangle(tempImage, g_rectangle); //进行绘制
}
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27) // 按下ESC键,程序退出
break;
}
return 0;
}
//------------------------【on_MouseHandle(函数)】------------
// 描述:鼠标回调函数,根据不同的鼠标事件进行不同的操作
//-----------------------------------------------------------
void on_MouseHandle(int event, int x, int y, int flags, void * param)
{
Mat & image = *(Mat*)param;
switch (event)
{
case EVENT_MOUSEMOVE:
{
if (g_bDrawingBox) //如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
{
g_rectangle.width = x - g_rectangle.x;
g_rectangle.height = y - g_rectangle.y;
}
}
break;
// 左键按下消息
case EVENT_LBUTTONDOWN:
{
g_bDrawingBox = true;
g_rectangle = Rect(x, y, 0, 0); //记录起点
}
break;
//左键抬起消息
case EVENT_LBUTTONUP:
{
// 标识符为false
g_bDrawingBox = false;
//对宽和高小于0的处理
if (g_rectangle.width < 0)
{
g_rectangle.x += g_rectangle.width;
g_rectangle.width *= -1;
}
if (g_rectangle.height < 0)
{
g_rectangle.y += g_rectangle.height;
g_rectangle.height *= -1;
}
//调用函数进行绘制
DrawRactangle(image, g_rectangle);
}
break;
}
}
void DrawRactangle(Mat & img, Rect box)
{
// tl(top left) br(below right)
rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)));
}
示例结果:
在此基础之上,我完成了一个鼠标框选截图的功能,代码如下:
// 鼠标框选截图
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
using namespace cv;
using namespace std;
//定义全局变量
#define WINDOW_NAME "鼠标框选截图"//窗口名
bool Draw_or_not = false;//是否绘图标识符
Rect Draw_Rect = Rect(-1, -1, 0, 0);//矩形框变量
/*---------------------------------------------------------【函数部分】---------------------------------------------------------------------*/
//绘图函数
//输入:图片地址,矩形框变量
//调用后在图中指定位置绘制白色矩形框
void DrawRactangle(Mat &image, Rect rect)
{
// tl(top left) br(below right)
rectangle(image, rect.tl(), rect.br(), Scalar::all(255));
}
//输出截图
//输入:原图,截取矩形框,新窗口名称
//调用后在新窗口中显示截取后的子图
void CroppedImage(Mat image, Rect rect, string window_name)
{
Mat cropped_image = image(rect);
imshow(window_name, cropped_image);
}
//鼠标回调函数,根据鼠标操作改变矩形框变量值,并绘制矩形框
void on_MouseHandle(int event, int x, int y, int flags, void * param)
{
Mat &image = *(Mat*)param;
//存储原图
Mat source_image;
image.copyTo(source_image);
//处理鼠标事件
switch (event)
{
case EVENT_MOUSEMOVE:
{
if (Draw_or_not) //如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
{
Draw_Rect.width = x - Draw_Rect.x;
Draw_Rect.height = y - Draw_Rect.y;
}
}
break;
// 左键按下消息
case EVENT_LBUTTONDOWN:
{
Draw_or_not = true;
Draw_Rect = Rect(x, y, 0, 0); //记录起点
}
break;
//左键抬起消息
case EVENT_LBUTTONUP:
{
// 标识符为false
Draw_or_not = false;
//对宽和高小于0的处理
if (Draw_Rect.width < 0)
{
Draw_Rect.x += Draw_Rect.width;
Draw_Rect.width *= -1;
}
if (Draw_Rect.height < 0)
{
Draw_Rect.y += Draw_Rect.height;
Draw_Rect.height *= -1;
}
//调用函数进行绘制
DrawRactangle(image, Draw_Rect);
//截图输出
CroppedImage(image, Draw_Rect, "截图");
//图像还原
source_image.copyTo(image);
}
break;
}
}
//主函数
int main()
{
//读取图片
Mat image = imread("image.jpg");
if (!image.data)
cout << "【图片读取失败】" << endl;
//临时图片
Mat tem_image;
//设置鼠标回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void *)&image);
while (waitKey(10) != 27)
{
image.copyTo(tem_image);
if(Draw_or_not)
DrawRactangle(tem_image, Draw_Rect);
imshow(WINDOW_NAME, tem_image);
}
}
运行结果: