【OpenCV 笔记】鼠标消息绘制矩形+截取ROI小窗口

学习资源来自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)));
}

效果如图:每次绘制的矩形都会保留,且每次的线条颜色均不同
【OpenCV 笔记】鼠标消息绘制矩形+截取ROI小窗口_第1张图片
那么是如何做到将每次的矩形都保留的呢?
代码中定义了两个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);
}

效果图:
【OpenCV 笔记】鼠标消息绘制矩形+截取ROI小窗口_第2张图片


【OpenCV 笔记】鼠标消息绘制矩形+截取ROI小窗口_第3张图片

你可能感兴趣的:(OpenCV)