opencv实现鼠标画矩形框、显示十字线、缩放图片

简介

实现一个在图片上框选区域的类,可以缩放图像方便操作,当图片过大的时候,只显示其中一部分,可以通过鼠标选定显示的区域中心。

材料收集

在csdn找到了两篇很有帮助的文章

第一篇,了解一下鼠标响应的基础
关于opencv2中鼠标响应操作.

我是在下面的项目下进行修改
opencv实现鼠标画矩形框、显示十字线、滚轮缩放.

开始设计

1,将鼠标响应函数封装到类

opencv的鼠标响应函数:

 CV_EXPORTS void setMouseCallback(const string& winname, MouseCallback onMouse, void* userdata = 0);  

在将普通的类成员函数,定义为鼠标响应函数时,会发生参数个数不匹配的问题,因为普通成员函数都‘隐藏’了一个参数,一个指向对象本身的指针this,我们可以通过this指针访问对象成员

// 相当于
//void DetetColor::setColorId(int id,int colorSize,DetetColor * this)
void DetetColor::setColorId(int id,int colorSize)
{
     this->id=id;
}

静态成员函数不能访问对象的普通成员函数,普通数据成员,所以默认不包括指向对象的指针this。我们通过void * 指针传入对象指针,访问对象成员函数

void displayPicture::on_Mouse_ComplexRect(int event, int x, int y,int flag)//实现画矩形框
{
	if (event == EVENT_RBUTTONDOWN)        //按下右键,减少一个已框选区域,重画
	{
	 。。。。
	}
}

void displayPicture::on_Mouse_ComplexRect(int events, int x, int y, int flag, void* userdata)
{
	displayPicture* temp = reinterpret_cast<displayPicture*>(userdata);
	temp->on_Mouse_ComplexRect( events,x,y,flag);
}

2.合理的显示图像

显示器的界面是有限的,图片是大小不一的,合理的显示图像应该考虑的
1.图片小于窗口,显示全部图片
2.图片大于窗口,根据选定的中心,显示部分图片
在这里插入图片描述

void displayPicture::showImageInRange()
{
	int x1,x2,y1,y2;
	Point zoomCenter=Point(imageCenter.x*scale,imageCenter.y*scale);
	if(zoomImage.cols<rangewidth)
	{
		x1=0;
		x2=zoomImage.cols-1;
	}
	else if(zoomCenter.x<rangewidth/2)
	{
		x1=0;
		x2=rangewidth;
	}
	else if(zoomImage.cols-rangewidth/2<zoomCenter.x)
	{
		x1=zoomImage.cols-rangewidth;
		x2=zoomImage.cols-1;
	}else
	{
		x1=zoomCenter.x-rangewidth/2;
		x2=zoomCenter.x+rangewidth/2;
	}

	if(zoomImage.rows<rangeheight)
	{
		y1=0;
		y2=zoomImage.rows-1;
	}
	else if(zoomCenter.y<rangeheight/2)
	{
		y1=0;
		y2=rangeheight;
	}
	else if(zoomImage.rows-rangeheight/2<zoomCenter.y)
	{
		y1=zoomImage.rows-rangeheight;
		y2=zoomImage.rows-1;
	}else
	{
		y1=zoomCenter.y-rangeheight/2;
		y2=zoomCenter.y+rangeheight/2;
	}

	Rect roi(x1,y1,x2-x1,y2-y1);
	rectOfRoi=roi;

	rectOfRoi.x/=scale;
	rectOfRoi.y/=scale;
	rectOfRoi.width/=scale;
	rectOfRoi.height/=scale;

	roiImage=zoomImage(roi);
}

全部代码

头文件

#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
class displayPicture
{
public:
	displayPicture(Mat image);
	~displayPicture(void);
	void display();

	//选定感兴趣区域,获得与图像大小相同的mask
	void getMask(Mat &mask);
    //选定不感兴趣区域,获得mask
	void getMaskINV(Mat &mask);

	int rangewidth;
	int rangeheight;

	vector<Rect> selectRect;


private:
	Mat srcImage;     
	Mat zoomImage;    //缩放的图片
	Mat roiImage;     //区域图像
	Mat showImage;	  //显示的图片
	
	Point imageCenter;  //图像的中心
	Rect rectOfRoi;
	Point g_center;
	bool select_flag;
	double scale;
	double step;

	string WINNAME;
	void changeScale(double newscale);
	void on_Mouse_ComplexRect(int event, int x, int y,int flag);
	static void on_Mouse_ComplexRect(int events, int x, int y, int, void* userdata);
	void drawAllRectangle();
	void draw_crossline(Mat &img, const Point &pt);

	void showImageInRange();

};

cpp文件

#include "displayPicture.h"

displayPicture::displayPicture(Mat image)
{
	scale=1;
	step=0.05;
	select_flag=false;
	rangewidth=1600;
	rangeheight=900;
	imageCenter=Point(0,0);
	WINNAME="画板";

	srcImage=image;
	zoomImage=srcImage.clone();
	showImageInRange();
	showImage=roiImage.clone();
}

displayPicture::~displayPicture(void)
{
}
void displayPicture::changeScale(double newscale)
{
	scale=newscale;
	if(newscale>1)
		scale=1;
	if(newscale<0.1)
		scale=0.1;

	resize(srcImage,zoomImage,Size(),scale,scale);
	showImageInRange();

	drawAllRectangle();
}

void displayPicture::display()
{
	namedWindow(WINNAME, 1);

	
	//添加鼠标相应
	setMouseCallback(WINNAME, displayPicture::on_Mouse_ComplexRect, this);
	
	drawAllRectangle();
	imshow(WINNAME,showImage);
	int key;
	while (1)
	{
		
		key = waitKey(40);
		if (key == ' ')
		{
			cv::destroyWindow(WINNAME);
			break;
		}
		else if (key == toascii('q'))
		{
			changeScale(scale -step);
			imshow(WINNAME,showImage);
			//zoom(mouseParam.img, mouseParam.imgZoomBackup, mouseParam.pt1, mouseParam.scale);
		}
		else if (key == toascii('e'))
		{
			changeScale(scale + step);
			imshow(WINNAME,showImage);
			//zoom(mouseParam.img, mouseParam.imgZoomBackup, mouseParam.pt1, mouseParam.scale);
		}
	}

}

void displayPicture::draw_crossline(Mat &img, const Point &pt)
{
	int width = img.cols;
	int height = img.rows;
	cv::Point ptv1;
	cv::Point ptv2;
	cv::Point pth1;
	cv::Point pth2;
	ptv1 = cv::Point(pt.x, 0);
	ptv2 = cv::Point(pt.x, height);
	pth1 = cv::Point(0, pt.y);
	pth2 = cv::Point(width, pt.y);

	cv::line(img, ptv1, ptv2, Scalar(255, 255, 0), 1);
	ptv1.x+=1;
	ptv2.x+=1;
	cv::line(img, ptv1, ptv2, Scalar(0, 0, 255), 1);

	cv::line(img, pth1, pth2, Scalar(255, 255, 0), 1);
	pth1.y+=1;
	pth2.y+=1;
	cv::line(img, pth1, pth2, Scalar(0, 0, 255), 1);
}

void displayPicture::showImageInRange()
{
	int x1,x2,y1,y2;
	Point zoomCenter=Point(imageCenter.x*scale,imageCenter.y*scale);
	if(zoomImage.cols<rangewidth)
	{
		x1=0;
		x2=zoomImage.cols-1;
	}
	else if(zoomCenter.x<rangewidth/2)
	{
		x1=0;
		x2=rangewidth;
	}
	else if(zoomImage.cols-rangewidth/2<zoomCenter.x)
	{
		x1=zoomImage.cols-rangewidth;
		x2=zoomImage.cols-1;
	}else
	{
		x1=zoomCenter.x-rangewidth/2;
		x2=zoomCenter.x+rangewidth/2;
	}

	if(zoomImage.rows<rangeheight)
	{
		y1=0;
		y2=zoomImage.rows-1;
	}
	else if(zoomCenter.y<rangeheight/2)
	{
		y1=0;
		y2=rangeheight;
	}
	else if(zoomImage.rows-rangeheight/2<zoomCenter.y)
	{
		y1=zoomImage.rows-rangeheight;
		y2=zoomImage.rows-1;
	}else
	{
		y1=zoomCenter.y-rangeheight/2;
		y2=zoomCenter.y+rangeheight/2;
	}

	Rect roi(x1,y1,x2-x1,y2-y1);
	rectOfRoi=roi;

	rectOfRoi.x/=scale;
	rectOfRoi.y/=scale;
	rectOfRoi.width/=scale;
	rectOfRoi.height/=scale;

	roiImage=zoomImage(roi);
}
void displayPicture::on_Mouse_ComplexRect(int event, int x, int y,int flag)//实现画矩形框
{
	static Point p1, p2;
	if (event == EVENT_RBUTTONDOWN)        //按下右键,减少一个已框选区域,重画
	{
//		selectRect.clear();
		selectRect.pop_back();
		drawAllRectangle();
		imshow(WINNAME, showImage);
	}
	else if ((flag&CV_EVENT_FLAG_CTRLKEY) &&event == EVENT_MOUSEMOVE)    //按下ctrl并移动鼠标
	{
		Mat temp;
		showImage.copyTo(temp);
		Point clickPoint(x,y);
		draw_crossline(temp, clickPoint);
		imshow(WINNAME, temp);
	}
	else if( event == EVENT_LBUTTONDOWN&&flag-event ==CV_EVENT_FLAG_CTRLKEY)  //Crtl+左键点击
	{
		imageCenter.x=rectOfRoi.x+x/scale;
		imageCenter.y=rectOfRoi.y+y/scale;
		showImageInRange();
		drawAllRectangle();
	}
	else if (event == EVENT_LBUTTONDOWN)     //左键点击
	{
		p1.x = x;
		p1.y = y;
		g_center=p1;
		select_flag = true;
	}
	else if (select_flag &&flag==CV_EVENT_FLAG_LBUTTON)   //鼠标拖拽
	{
		Mat temp;
		showImage.copyTo(temp);
		p2 = Point(x, y);
		rectangle(temp, p1, p2, Scalar(0, 255, 0), 2);
		imshow(WINNAME, temp);
	}
	else if (select_flag && event == EVENT_LBUTTONUP)     //松开鼠标
	{
		Rect roi = Rect(p1, Point(x, y));
		if (roi.width && roi.height)//点一下时会没有反应
		{
			roi.x/=scale;
			roi.y/=scale;
			roi.width/=scale;
			roi.height/=scale;
			roi.x+=rectOfRoi.x;
			roi.y+=rectOfRoi.y;


			selectRect.push_back(roi);
			drawAllRectangle();
		}
		select_flag = false;
	}
	
}

void displayPicture::on_Mouse_ComplexRect(int events, int x, int y, int flag, void* userdata)
{
	displayPicture* temp = reinterpret_cast<displayPicture*>(userdata);
	temp->on_Mouse_ComplexRect( events,x,y,flag);
}

void displayPicture::drawAllRectangle()
{
	showImage=roiImage.clone();

	for(int i=0;i<selectRect.size();i++)
	{
		Scalar color(125,255,0);

		Rect rect=selectRect[i];
		rect.x-=rectOfRoi.x;
		rect.y-=rectOfRoi.y;
		rect.x*=scale;
		rect.y*=scale;
		rect.width*=scale;
		rect.height*=scale;

		rectangle(showImage,rect,color,2);
	}
	string  temp="zoom with 'q' or 'e' ,set the Image center with ctrl+click ,out with space";  //将鼠标点击的二维坐标显示到屏幕上
	cv::putText(showImage,temp,Point(0, 16), FONT_HERSHEY_PLAIN, 1.f, Scalar(120, 255, 125), 1);
//	imshow(WINNAME, showImage);
}

//选定感兴趣区域,获得与图像大小相同的mask
void displayPicture::getMask(Mat &mask)
{
	display();
	mask=Mat::zeros(srcImage.rows,srcImage.cols,CV_8U);
	Mat all255(srcImage.rows,srcImage.cols,CV_8U,Scalar(255));

	for(int i=0;i<selectRect.size();i++)
	{
		Mat roi=mask(selectRect[i]);
		Mat roi2=all255(selectRect[i]);
		roi2.copyTo(roi);
	}

	//显示mask
	displayPicture displayMask(mask);
	displayMask.display();

}
//选定不感兴趣区域,获得mask
void displayPicture::getMaskINV(Mat &mask)
{
	display();
	mask=Mat(srcImage.rows,srcImage.cols,CV_8U,Scalar(255));
	Mat allZeros=Mat::zeros(srcImage.rows,srcImage.cols,CV_8U);

	for(int i=0;i<selectRect.size();i++)
	{
		Mat roi=mask(selectRect[i]);
		Mat roi2=allZeros(selectRect[i]);
		roi2.copyTo(roi);
	}

	//显示mask
	displayPicture displayMask(mask);
	displayMask.display();

项目资源

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值