opencv图像相似度

  • opencv图像相似度多种方法(可以直接用两张图片相减)


opencv图像相似度多种方法(可以直接用两张图片相减)

#include <iostream>  
#include <opencv2/opencv.hpp>



#include <opencv2\opencv.hpp>  
#include <opencv2\core\core.hpp>  
#include <opencv2\highgui\highgui.hpp>  
#include <opencv2\imgproc\imgproc.hpp>  
#include <opencv2\objdetect\objdetect.hpp>  
#include <opencv2\imgproc\types_c.h>   
#include <iostream>
#include <string>
#include <stdlib.h>


using namespace std;
using namespace cv;


//TM_SQDIFF:平方差匹配法,该方法采用平方差进行匹配,最好的匹配值为0;匹配越差,匹配值越大
//
//TM_SQDIFF_NORMED:归一化平方差匹配法
//
//TM_CCORR:相关匹配法,该方法采用乘法操作,数值越大表示匹配程度越好
//
//TM_CCORR_NORMED:归一化相关匹配法
//
//TM_CCOEFF:相关系数匹配法,1表示完美的匹配, - 1表示最差的匹配
//
//TM_CCOEFF_NORMED:归一化相关系数匹配法




//cv2.TM_CCOEFF:系数匹配法,计算相关系数,计算出来的值越大,越相关
//cv2.TM_CCOEFF_NORMED:相关系数匹配法,计算归一化相关系数,计算出来的值越接近1,越相关
//cv2.TM_CCORR:相关匹配法,计算相关性,计算出来的值越大,越相关
//cv2.TM_CCORR_NORMED:归一化相关匹配法,计算归一化相关性,计算出来的值越接近1,越相关
//cv2.TM_SQDIFF:平方差匹配法,计算平方不同,计算出来的值越小,越相关
//cv2.TM_SQDIFF_NORMED:归一化平方差匹配法,计算归一化平方不同,计算出来的值越接近0,越相关

//模板匹配
void Template(Mat img,Mat img_temp)
{

	const char* str_Input_Window_Title = "Read Image Window";
	const char* str_Output_Window_Title = "Result Window";
	const char* str_Template_Window_Title = "Template Window";

	int matchMethod = 5;

	
	//imshow(str_Input_Window_Title, img);
	//imshow(str_Template_Window_Title, img_temp);

	Mat dst;
	dst.create(img.size(), img.type());//实践证明,result在初始化时可以不用设定为模板匹配中要求宽高
	matchTemplate(img, img_temp, dst, matchMethod);//method选择TM_SQDIFF_NORMED,越接近0,匹配度越高
	//imshow("Match Window", dst);//显示匹配后的图像
	// 
	//normalize(dst, dst, 0, 1, NORM_MINMAX, -1);//根据所选的method决定是否归一化

	double min_value, max_value;
	Point Point_Max, Point_Min, temLoc;
	minMaxLoc(dst, &min_value, &max_value, &Point_Min, &Point_Max);//寻找最小值点


	if (matchMethod == 0 || matchMethod == 1)
	{
		temLoc = Point_Min;
	}
	else
	{
		temLoc = Point_Max;
	}


	printf("Max:%4f   Min:%4f\nX:%d   Y:%d\n", max_value, min_value, Point_Min.x, Point_Min.y);
	//imshow(str_Output_Window_Title, dst);
	//在原图像中圈出匹配到的目标区域
	//rectangle(img, Rect(Point_Min.x, Point_Min.y, img_temp.cols, img_temp.rows), Scalar(0, 0, 255), 2, 8);
	rectangle(img, Rect(temLoc.x, temLoc.y, img_temp.cols, img_temp.rows), Scalar(0, 0, 255), 2);
	//imshow(str_Output_Window_Title, img);//显示原图像

	/*waitKey(0);
	destroyAllWindows();*/

	


}



//phash感知哈希
string pHashValue(Mat& srcImg)//pHash方法计算图片哈希值
{
	Mat img, dstImg;
	string rst(64, '\0');

	double dIndex[64];
	double mean = 0.0;
	int  k = 0;

	if (srcImg.channels() == 3)//若为彩色图像则转换为灰度图像
	{
		cvtColor(srcImg, srcImg, CV_BGR2GRAY);
		img = Mat_<double>(srcImg);
	}
	else
	{

		img = Mat_<double>(srcImg);

	}

	//缩放尺寸
	resize(img, img, Size(32, 32));
	//离散余弦变换 DCT
	dct(img, dstImg);

	//获取dct系数均值
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			dIndex[k] = dstImg.at<double>(i, j);
			//计算每个像素的均值
			mean += dstImg.at<double>(i, j) / 64;
			++k;
		}
	}

	//计算hash
	for (int i = 0; i < 64; ++i)
	{
		if (dIndex[i] >= mean)
		{
			rst[i] = '1';
		}
		else {
			rst[i] = '0';
		}
	}

	return rst;

}
int hanmingDist(string& str1, string& str2)//计算哈希值字符串的汉明距离
{
	if ((str1.size() != 64) || (str2.size() != 64))
	{
		return -1;
	}

	int distValue = 0;
	for (int i = 0; i < 64; i++)
	{
		if (str1[i] != str2[i])
		{
			distValue++;
		}
	}

	return distValue;

}


void MyHash(Mat img, Mat img_temp) {

	
	/*imshow("OrgImg", img);
	imshow("Img", img_temp);*/

	string str1 = pHashValue(img);
	string str2 = pHashValue(img_temp);

	int distance = hanmingDist(str1, str2);
	cout << "两张图片的汉明距离:" << distance << endl;

	if (distance < 5) //若汉明距离小于5,则两张图片相似
	{
		cout << "两张图片相似" << endl;
	}
	else
	{
		cout << "两张图片不相似" << endl;
	}

	/*waitKey(0);
	destroyAllWindows();*/


}






//直方图
void MyHist(Mat sr1, Mat sr2) {



	//1. 载入图像(灰度图或者彩色图),并使其大小一致;

	//2. 若为彩色图,增进行颜色空间变换,从RGB转换到HSV,若为灰度图则无需变换;

	//3. 若为灰度图,直接计算其直方图,并进行直方图归一化;

	//4. 若为彩色图,则计算其彩色直方图,并进行彩色直方图归一化;

	//5. 使用相似度公式,如相关系数、卡方、相交或巴氏距离,计算出相似度值。
	 //compareHist 

	cv::Mat matDst1, matDst2;

	sr1.copyTo(matDst1);
	sr2.copyTo(matDst2);
	/*matDst1 = sr1;
	matDst2 = sr2;*/


	cv::Size sizeImage = cv::Size(500, 500);
	if (matDst1.channels() == 1) {
		cv::resize(matDst1, matDst1, sizeImage);
		//cv::flip(matDst1, matDst1, 1);
		cv::resize(matDst2, matDst2, sizeImage);
		int histSize = 256;
		float range[] = { 0, 256 };
		const float* histRange = { range };
		bool uniform = true;
		bool accumulate = false;
		cv::Mat hist1, hist2;
		cv::calcHist(&matDst1, 1, 0, cv::Mat(), hist1, 1, &histSize, &histRange, true, false);
		cv::normalize(hist1, hist1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());
		cv::calcHist(&matDst2, 1, 0, cv::Mat(), hist2, 1, &histSize, &histRange, true, false);
		cv::normalize(hist2, hist2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());

		//compareHist 

		cout << "similarity0 = " << cv::compareHist(hist1, hist2, 0) << endl;
		cout << "similarity1 = " << cv::compareHist(hist1, hist2, 1) << endl;
		cout << "similarity2 = " << cv::compareHist(hist1, hist2, 2) << endl;
		cout << "similarity3 = " << cv::compareHist(hist1, hist2, 3) << endl;


	}
	else {
		cv::cvtColor(matDst1, matDst1, cv::COLOR_BGR2HSV);
		cv::cvtColor(matDst2, matDst2, cv::COLOR_BGR2HSV);
		int h_bins = 60, s_bins = 64, v_bins = 64;
		int histSize[] = { h_bins, s_bins,v_bins };
		float h_ranges[] = { 0, 180 };
		float s_ranges[] = { 0, 256 };
		float V_ranges[] = { 0, 256 };
		const float* ranges[] = { h_ranges, s_ranges,V_ranges };
		int channels[] = { 0,1, 2 };
		cv::MatND hist1, hist2;
		int width = 400;
		int height = 600;
		cv::calcHist(&matDst1, 1, channels, cv::Mat(), hist1, 3, histSize, ranges, true, false);
		cv::normalize(hist1, hist1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());
		cv::calcHist(&matDst2, 1, channels, cv::Mat(), hist2, 3, histSize, ranges, true, false);
		cv::normalize(hist2, hist2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());
		double t = 1 - cv::compareHist(hist1, hist2, 3);
		cv::normalize(hist2, hist2, 0, height, cv::NORM_MINMAX, -1, cv::Mat());
		cv::normalize(hist1, hist1, 0, height, cv::NORM_MINMAX, -1, cv::Mat());


		cout << "similarity0 = " << cv::compareHist(hist1, hist2, 0) << endl;
		cout << "similarity1 = " << cv::compareHist(hist1, hist2, 1) << endl;
		cout << "similarity2 = " << cv::compareHist(hist1, hist2, 2) << endl;
		cout << "similarity3 = " << cv::compareHist(hist1, hist2, 3) << endl;
	}
}


//ssim
double ssimDetect(Mat sr1, Mat sr2)
{
	double C1 = 6.5025, C2 = 58.5225;
	cv::Mat image_ref, image_obj;
	sr1.copyTo(image_ref);
	sr2.copyTo(image_obj);
	
	cv::Size sizeImage = cv::Size(500, 500);
	cv::resize(image_ref, image_ref, sizeImage);
	cv::resize(image_obj, image_obj, sizeImage);

	int width = image_ref.cols;
	int height = image_ref.rows;
	int width2 = image_obj.cols;
	int height2 = image_obj.rows;
	double mean_x = 0;
	double mean_y = 0;
	double sigma_x = 0;
	double sigma_y = 0;
	double sigma_xy = 0;
	for (int v = 0; v < height; v++)
	{
		for (int u = 0; u < width; u++)
		{
			mean_x += image_ref.at<uchar>(v, u);
			mean_y += image_obj.at<uchar>(v, u);

		}
	}
	mean_x = mean_x / width / height;
	mean_y = mean_y / width / height;
	for (int v = 0; v < height; v++)
	{
		for (int u = 0; u < width; u++)
		{
			sigma_x += (image_ref.at<uchar>(v, u) - mean_x) * (image_ref.at<uchar>(v, u) - mean_x);
			sigma_y += (image_obj.at<uchar>(v, u) - mean_y) * (image_obj.at<uchar>(v, u) - mean_y);
			sigma_xy += abs((image_ref.at<uchar>(v, u) - mean_x) * (image_obj.at<uchar>(v, u) - mean_y));
		}
	}
	sigma_x = sigma_x / (width * height - 1);
	sigma_y = sigma_y / (width * height - 1);
	sigma_xy = sigma_xy / (width * height - 1);
	double fenzi = (2 * mean_x * mean_y + C1) * (2 * sigma_xy + C2);
	double fenmu = (mean_x * mean_x + mean_y * mean_y + C1) * (sigma_x + sigma_y + C2);
	double ssim = fenzi / fenmu;
	return ssim;
}




int main()
{
	//Mat img = imread("./images/no/5.bmp");//从指定路径加载图像
	//Mat img_temp = imread("./images/ok/1.bmp");
	Mat img = imread("./chess.png");//从指定路径加载图像
	Mat img_temp = imread("./chess_template.png");
	Mat img_temp = imread("./chess_template.png");
	//if (!img.data || !img_temp.data)//加载图像失败
	//{
	//	printf("Fault to load image!\n\r");
	//	return -1;
	//}

	//double ssim=ssimDetect(img, img_temp);
	//cout << "ssim:" << ssim << endl;

	//MyHist(img, img_temp);
	//Template(img,img_temp);

	//MyHash(img, img_temp);


	Mat img_temp = imread("./images/ok/1.bmp");

	cv::String mypath = "images/no/*.bmp";
	vector<cv::String> fn;
	glob(mypath, fn, false);
	vector<Mat> images;
	size_t count = fn.size(); //number of png files in images folder
	for (size_t i = 0; i < count; i++)
	{   
		cout << ".............................第"<<i << "轮..........................." << endl;

		Mat img = cv::imread(fn[i]);
		double ssim = ssimDetect(img, img_temp);
		cout << "ssim:" << ssim << endl;

		MyHist(img, img_temp);
		Template(img, img_temp);
		MyHash(img, img_temp);
		/*images.emplace_back(cv::imread(fn[i]));
		imshow("img", imread(fn[i]));
		waitKey(0);*/
	}



	
	return 0;
}

python 计算两张图片的相似度 余弦 opencv计算两张图片相似度_#include