MFC中使用OpenCV动态绘制图像ROI区域(矩形+多边形)

MFC中使用OpenCV动态绘制图像ROI区域(矩形+多边形)

  • [1 环境](#1 环境)
  • [2 绘制矩形](#2 绘制矩形)
  • [3 绘制多边形](#3 绘制多边形)
  • [4 参考文章](#4 参考文章)

在MFC中,使用Opencv的鼠标事件实现图像的矩形、多边形ROI区域选择。

通过设置鼠标回调函数,监听鼠标的点击、移动、拖拽等操作,动态的在图像上绘制矩形或多边形。并利用选择的矩形或多边形所形成的Mask,提取图像上的ROI区域。

1 环境

OpenCV 4.8

Visual Studio 2015

2 绘制矩形

(1)左键按下时,鼠标移动,在临时图像上实时显示鼠标拖动时形成的矩形。

(2)左键松开时,根据初始点和结束点,将矩形绘制到图像上。

(3)鼠标移动时,实时显示当前点坐标。

cpp 复制代码
void on_mouse_rect(int event, int x, int y, int flags, void *ustc)-
{
	char temp[16];  
	if (event == CV_EVENT_LBUTTONDOWN)
	{
		m_show.copyTo(img);
		pre_pt = cv::Point(x, y);
		circle(img, pre_pt, 2, cv::Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);
		cv::imshow("view", img);
	}
	else if (event == CV_EVENT_MOUSEMOVE && !(flags & CV_EVENT_FLAG_LBUTTON))  
	{
		img.copyTo(tmp);
		sprintf(temp,"(%d,%d)",x,y); 
		cur_pt = cv::Point(x, y);
		putText(tmp,temp,cur_pt,cv::FONT_HERSHEY_SIMPLEX,0.5,cv::Scalar(0,0,0,255),2);
		cv::imshow("view", tmp);
	}
	else if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON)) 
	{
		//-- 为了打开图像时不展示鼠标操作
		if (pre_pt.x == -1 && pre_pt.y == -1) {
			return;
		}
		m_show.copyTo(tmp);
		sprintf(temp, "(%d,%d)", x, y);
		cur_pt = cv::Point(x, y);
		putText(tmp, temp, cur_pt, cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0, 255),2);
		rectangle(tmp, pre_pt, cur_pt, cv::Scalar(0, 0, 0, 255), 2, 8, 0);
		cv::imshow("view", tmp);
	}
	else if (event == CV_EVENT_LBUTTONUP)  
	{
		if (pre_pt.x == -1 && pre_pt.y == -1) {
			return;
		}
		//-- show view
		m_show.copyTo(img);
		cur_pt = cv::Point(x, y);
		circle(img, pre_pt, 2, cv::Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);
		rectangle(img, pre_pt, cur_pt, cv::Scalar(0, 0, 0, 255), 2, 8, 0);
		cv::imshow("view", img);

		//-- get rect 
		int width = abs(pre_pt.x - cur_pt.x);
		int height = abs(pre_pt.y - cur_pt.y);
		if (width == 0 || height == 0)
		{
			printf("width == 0 || height == 0");
			return;
		}
		//-- show roi
		cv::Rect roiRect = cv::Rect(
			(int)std::min(cur_pt.x, pre_pt.x), 
			(int)std::min(cur_pt.y, pre_pt.y), 
			width, 
			height);
		roiRect = roiRect & cv::Rect(0, 0, m_show.cols, m_show.rows);
		cv::Mat showRoi = m_show(roiRect);
		cv::resize(showRoi, showRoi, cv::Size(m_rectRoi.Width(), m_rectRoi.Height()));

		HWND hWndRoi = (HWND)cvGetWindowHandle("roi");
		::ShowWindow(hWndRoi, SW_SHOWNORMAL);
		cv::imshow("roi", showRoi);
	}
}

3 绘制多边形

(1)左键按下时,选择点,并与上一次选择的点连成线实时显示。

(2)右键按下时,取消最近一次选择的点。

(3)中间键按下时,绘制由所选择的点组成的多边形的轮廓。

(4)鼠标移动时,实时显示当前点坐标。

cpp 复制代码
void on_mouse_polygon(int event, int x, int y, int flags, void *ustc)//event鼠标事件代号,x,y鼠标坐标,flags拖拽和键盘操作的代号  
{
	m_show.copyTo(img);
	char temp[16];
	if (event == CV_EVENT_LBUTTONDOWN)
	{
		if (m_bPolygonFinished) {
			pts.clear();
		}
		m_bPolygonFinished = false;
		pts.push_back(cv::Point(x, y));
	}
	if (event == CV_EVENT_RBUTTONDOWN) 
	{
		m_bPolygonFinished = false;
		pts.pop_back();
	}
	if (event == CV_EVENT_MBUTTONDOWN)
	{
		//-- roi选完
		m_bPolygonFinished = true;

		//-- 展示区 mask提取
		cv::Mat mask = cv::Mat::zeros(m_show.size(), CV_8UC1);
		cv::fillPoly(mask, pts, cv::Scalar(255), 8, 0);
		cv::Mat dst;
		cv::bitwise_and(img, img, dst, mask);
		//-- 展示区 roi mask外接矩形展示
		cv::Rect rt = cv::boundingRect(mask);
		cv::resize(dst(rt), dst, cv::Size(m_rectRoi.Width(), m_rectRoi.Height()));
		HWND hWndRoi = (HWND)cvGetWindowHandle("roi");
		::ShowWindow(hWndRoi, SW_SHOWNORMAL);
		cv::imshow("roi", dst);
	}
	if(event == CV_EVENT_MOUSEMOVE && !(flags & CV_EVENT_FLAG_LBUTTON))  
	{
		sprintf(temp, "(%d,%d)", x, y); 
		cur_pt = cv::Point(x, y);
		putText(img, temp, cur_pt, cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0, 255), 2); 
		cv::imshow("view", img);
	}

	int num = pts.size();
	if (num > 0)	
		circle(img, pts[num - 1], 2, cv::Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);

	if (num > 1) {
		for (int i = 0; i < num - 1; i++) {
			cv::circle(img, pts[i], 2, cv::Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);
			cv::line(img, pts[i], pts[i + 1], cv::Scalar(255, 0, 0), 2);
		}
		if (m_bPolygonFinished)
			cv::line(img, pts[0], pts[num - 1], cv::Scalar(255, 0, 0), 2);
	}
	cv::imshow("view", img);     
}

4 参考文章

MFC 绘制图像ROI区域(OpenCv库)
Opencv鼠标事件+界面交互之绘制矩形多边形选取感兴趣区域ROI

相关推荐
小七在进步8 小时前
string的使用(1)
c++·visual studio
白杨尚青9 小时前
C++进阶篇(六):map 和 set 的模拟实现——用红黑树封装 mymap/myset(迭代器 + operator[])
开发语言·c++·迭代器·stl·set·map·红黑树
kloc11 小时前
聊天室项目入口网关子服务的实现
linux·c++
csdn_aspnet14 小时前
C++ 3个有序点的方向(Orientation of 3 ordered points)
c++·算法
小七在进步15 小时前
string的使用(2)
c++
青少儿编程课堂16 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:折半搜索优化子集枚举(Meet in the Middle)解析
c++·python·算法·bfs·信息学竞赛
wo_jack18 小时前
C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?
数据结构·c++·面试·stl·list
青少儿编程课堂19 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园连连看解析
c++·python·算法·bfs·信息学竞赛
草莓熊Lotso19 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试
David猪大卫2 天前
【C++修炼】map 和 set 的使用
c语言·开发语言·数据结构·c++·经验分享·笔记·学习