学习资源来自CSDN大佬浅墨的著作《OpenCV3编程入门》
首先附上书籍中利用鼠标消息绘制矩形的C++代码:
/*动态绘制矩形*/
#include "stdafx.h"
#include
using namespace cv;
#define WINDOW_NAME "鼠标绘制矩形"
void on_MouseHandle(int event, int x, int y, int flags, void* param);
void DrawRectangle(Mat& img, Rect box);
Rect g_rectangle;
bool g_bDrawingBox = false;
RNG g_rng(12345);//RNG是随机数生成器
int main()
{
Mat srcImg(600, 800, CV_8UC3)/*8位3通道图像*/, tempImage;
srcImg = Scalar::all(0);//全黑
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)&srcImg);
while (1)
{
/*形成拖动矩形*/
srcImg.copyTo(tempImage);//每次都用srcImg覆盖一下画面,当鼠标弹起时才会改变srcImg
if (g_bDrawingBox)
DrawRectangle(tempImage, g_rectangle);
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27) break;
}
return 1;
}
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
Mat& image = *(Mat*)param;//先从空指针转换为Mat指针再解引用
switch (event)
{
case EVENT_MOUSEMOVE:
{
if (g_bDrawingBox)
{
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:
{
g_bDrawingBox = false;
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;
}
DrawRectangle(image, g_rectangle);
}
break;
}
}
void DrawRectangle(Mat& img, Rect box)
{
rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0, 255),
g_rng.uniform(0, 255), g_rng.uniform(0, 255)));
}
效果如图:每次绘制的矩形都会保留,且每次的线条颜色均不同
那么是如何做到将每次的矩形都保留的呢?
代码中定义了两个Mat对象,srcImg和tempImage,简单地说前者用于实现保留之前矩形图案,后者用于实现鼠标按下拖动时的动态矩形框。在while循环中,每次都要将srcImg赋给tempImage,tempImage再根据if条件判断是否应该绘制矩形,并将结果显示。而srcImg只有在鼠标抬起时才会改变,因为setMouseCallback最后的参数是srcImg,在EVENT_LBUTTONUP这个事件中会对srcImg进行矩形绘制。
由于OpenCV主要是对视频图像进行处理,博主在对上述代码理解后,进行了一些拓展。
实现功能:1.读入视频,利用滚动条控制视频的暂停播放
2.使用矩形框选取视频的部分界面,并在新窗口进行显示,如果感觉选的不好,可以对原视频在此绘制矩形重新选取
3.截取后的部分存在SmallFrame中,便于后续对这一部分的图像进行处理
C++代码如下:
#include "stdafx.h"
#include
using namespace cv;
#define WINDOW_MAIN "视频窗口"
#define WINDOW_NEW "截取窗口"
/*定义全局变量和函数*/
VideoCapture capture;
Mat Frame;
Mat NewFrame;
Mat SmallFrame;
Rect g_rectangle;
bool g_bDrawingBox = false;
bool g_bDrawFinished = false;
int g_PlaySlider = 0;
void on_MouseHandle(int event, int x, int y, int flags, void* param);
void DrawRectangle(Mat& img, Rect box);
int main()
{
namedWindow(WINDOW_MAIN);
createTrackbar("trackbar", WINDOW_MAIN, &g_PlaySlider, 1);
/*显示视频第一帧的静止画面,拖动条为0暂停,为1继续*/
capture = VideoCapture("图像文件.avi");
capture >> Frame;
if (!capture.isOpened() || Frame.empty())
return false;
imshow(WINDOW_MAIN, Frame);
/*绑定鼠标事件*/
setMouseCallback(WINDOW_MAIN, on_MouseHandle, (void*)&NewFrame);
while (!Frame.empty())
{
/*形成拖动矩形*/
Frame.copyTo(NewFrame);
DrawRectangle(NewFrame, g_rectangle);
imshow(WINDOW_MAIN, NewFrame);
if (g_bDrawFinished)
{
SmallFrame = NewFrame(Rect(g_rectangle.x, g_rectangle.y,
g_rectangle.width, g_rectangle.height));
imshow(WINDOW_NEW, SmallFrame);
}
/*拖动条为1的话更新视频帧,否则只更新矩形*/
if (g_PlaySlider)
capture >> Frame;
waitKey(42);
}
return 0;
}
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)
{
g_rectangle.width = x - g_rectangle.x;
g_rectangle.height = y - g_rectangle.y;
}
}
break;
case EVENT_LBUTTONDOWN:
{
g_bDrawFinished = false;
g_bDrawingBox = true;
g_rectangle = Rect(x, y, 0, 0);
}
break;
case EVENT_LBUTTONUP:
{
g_bDrawingBox = false;
g_bDrawFinished = true;
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;
}
DrawRectangle(image, g_rectangle);
}
break;
}
}
void DrawRectangle(Mat& img, Rect box)
{
rectangle(img, box.tl(), box.br(), Scalar(225,
105, 65), 2);
}