opencv2鼠标选定感兴趣区域用反投影算法检测相似部分

本文介绍了如何结合OpenCV的鼠标事件和反投影算法,通过用户选择的感兴趣区域(ROI)来检测图像中相似的部分。文章提供了具体的实现过程,并给出了运行结果。
摘要由CSDN通过智能技术生成

请广大博友转载时,注明文章出处,谢谢!!!

这个是对上一篇,在反投影算法中使用颜色信息的一个拓展,理解了上一篇和鼠标事件后,这个就是组合

#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/imgproc/types_c.h>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<iostream>
#include<vector>
#include<opencv2/nonfree/features2d.hpp>
#include<opencv2/legacy/legacy.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/calib3d/calib3d.hpp>
#include<opencv2/video/tracking.hpp>

using namespace cv;
using namespace std;

class Package
{
private:

public:
	Mat CalcBack_Color(const Mat &InImage, const Rect &rectROI);
	MatND ComterGrayHistogram(const Mat &InImage, bool isdisplay, bool isshow, const Scalar &color, int channelsnum);
	Mat colorReduce(const Mat &InImage, int div);
};

Mat Package::colorReduce(const Mat &InImage, int div)
{
	Mat OutImage(InImage.rows, InImage.cols, InImage.type());
	int x = InImage.rows;
	int y = InImage.cols*InImage.channels();

	for (int i = 0; i < x; i++)
	{
		const uchar* data = InImage.ptr<const uchar>(i);
		uchar* data_out = OutImage.ptr<uchar>(i);

		for (int j = 0; j < y; j++)
		{
			data_out[j] = data[j] / div*div + div / 2;
		}
	}

	return OutImage;
}

Mat Package::CalcBack_Color(const Mat &InImage, const Rect &rectROI)
{
	Mat OutImage = InImage;

	//先初始化一些变量,在函数中用做中间参数使用
	float hranges[2];    //最小值和最大值
	const float *ranges[3];
	int channels[3];
	MatND histogram;
	int histSize[3];

	ranges[0] = hranges;
	ranges[1] = hranges;
	ranges[2] = hranges;

	hranges[0] = 0.0;
	hranges[1] = 255.0;

	channels[0] = 0;
	channels[1] = 1;
	channels[2] = 2;

	histSize[0] = 256;
	histSize[1] = 256;
	histSize[2] = 256;

	//使用颜色减缩函数
	OutImage = colorReduce(OutImage, 32);

	Mat OutImageROI = OutImage(rectROI);

	MatND hist;
	calcHist(&OutImageROI, 1, channels, Mat(), hist, 3, histSize, ranges);
	normalize(hist, hist, 1.0);

	Mat result;
	calcBackProject(&OutImage, 1, channels, hist, result, ranges, 255.0);

	cout << "OK" << endl;

	return result;
}

MatND Package::ComterGrayHistogram(const Mat &InImage, bool isdisplay, bool isshow, const Scalar &color, int channelsnum)
{
	Mat GrayImage;
	vector<Mat>channelsvector;
	if (InImage.channels() == 3)
	{
		split(InImage, channelsvector);

		if (channelsnum == 0)
		{
			cvtColor(InImage, GrayImage, CV_BGR2GRAY);
		}

		if (channelsnum == 1)
		{
			GrayImage = channelsvector[0];
		}

		if (channelsnum == 2)
		{
			GrayImage = channelsvector[1];
		}

		if (channelsnum == 3)
		{
			GrayImage = channelsvector[2];
		}
	}
	else
	{
		GrayImage = InImage;
	}

	//通道数
	int channels[1];
	//计算0号通道
	channels[0] = 0;
	//项的数量
	int histSize[1];
	histSize[0] = 256;
	//像素值的范围
	const float *ranges[1];

	//像素的最小及最大值,为了给hranges一个变量的分配的空间
	float hranges[2];
	ranges[0] = hranges;

	//存放最小范围
	hranges[0] = 0;
	//存放最大范围
	hranges[1] = 255;

	MatND hist;
	calcHist(&GrayImage, 1, channels, Mat(), hist, 1, histSize, ranges);

	if (isdisplay == 1)
	{
		for (int i = 0; i < 256; i++)
		{
			cout << "Value" << i << "=" << hist.at<float>(i) << endl;
		}
	}

	/*开始直观的显示出直方图,如果将isshow置零,将不显示*/
	if (isshow == 1)
	{
		double minVal;
		double maxVal;

		//找到数组的最大值和最小值,目的是需要用最大和最小值将得到的对应像素的像素点个数归一化,这里的归一化是都归在0~255之间
		//这个处理仅仅是为了显示起来方便,如果不规定一个统一的最大值,那么显示的尺寸就要就会随着最大值在不断的变换
		minMaxLoc(hist, &minVal, &maxVal, 0, 0);

		//定义显示直方图的Mat型,包括显示窗口的长度和宽度
		//这里就把最大值限制在histSize[0]上了
		Mat showhist(histSize[0], histSize[0], CV_8UC3, Scalar(255, 255, 255));

		//将最高点设置为横坐标总长的90%,最大值就不会超过256*0.9,这样在一个正好是256*256的图像中就不会有值刚好在边界上,增强了可视化
		int hpt = static_cast<int>(0.9*histSize[0]);

		for (int x = 0; x < histSize[0]; x++)       //绘制直方图
		{
			//得到每个像素点对应的像素的个数
			float binVal = hist.at<float>(x);
			int intensity = static_cast<int>(binVal*hpt / maxVal);

			//由于图像的y轴是竖直向下的,所以连线的时候起始坐标是(x, histSize[0]),而不是(0, 0))
			line(showhist, Point(x, histSize[0]), Point(x, histSize[0] - intensity), color);
		}
	}

	return hist;
}

Package P;

Point coord;//储存初始坐标
Rect sqart;//储存矩形框的起始坐标以及长度和宽度
bool draw;
Mat img;//过度图像
Mat dst;//感兴趣区域图像
Mat org;//将org作为原始图像储存

void onMouse(int event, int x, int y, int flags, void *param)
{
	/*cout << "Event:" << event << endl;
	cout << "x=" << x << "     " << "y=" << y << endl;
	cout << "flags:" << endl;
	cout << "param" << param << endl;*/

	switch (event)
	{
		//按下鼠标左键
	case CV_EVENT_LBUTTONDOWN:
		//在第二次点击鼠标图像时,这里清除了一下显示小窗口的步骤
		cvDestroyWindow("dst");
		//储存起始坐标
		coord = Point(x, y);
		//将起始矩形框初始化
		sqart = Rect(x, y, 0, 0);
		draw = true;
		break;

		//松开鼠标左键
	case CV_EVENT_LBUTTONUP:
		if (sqart.height > 0 && sqart.width > 0)
		{
			//将img中的矩形区域复制给dst,并显示在img窗口中
			dst = img(Rect(sqart.x, sqart.y, sqart.width, sqart.height));
			rectangle(img, sqart, Scalar(0, 0, 255), 1);
			namedWindow("img");
			imshow("img", img);

			//将画过矩形框的图像用org原图像还原
			org.copyTo(img);
			imshow("Mouse", img);

			Mat calc = P.CalcBack_Color(img, Rect(sqart.x, sqart.y, sqart.width, sqart.height));
			namedWindow("calc");
			imshow("calc", calc);

			namedWindow("dst");
			imshow("dst", dst);
			waitKey(0);
		}
		draw = false;
		break;

	case CV_EVENT_MOUSEMOVE:
		if (draw/*&&sqart.height > 0 && sqart.width > 0*/)
		{
			//用MIN得到左上点作为矩形框的其实坐标,如果不加这个,画矩形时只能向一个方向进行
			sqart.x = MIN(x, coord.x);
			sqart.y = MIN(y, coord.y);
			sqart.width = abs(coord.x - x);
			sqart.height = abs(coord.y - y);
			//防止矩形区域超出图像的范围
			sqart &= Rect(0, 0, org.cols, org.rows);
		}
		break;
	}
}

int main()
{
	img = imread("F:\\color.jpg");
	namedWindow("Mouse");
	setMouseCallback("Mouse", onMouse, NULL);
	imshow("Mouse", img);

	img.copyTo(org);//将org作为原始图像储存

	waitKey(0);

	return 0;
}


运行结果:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值