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;
}