今天自己写了一个简单的计算图相似度的算法,借鉴了哈希算法思想进行编写,在此分享给大家!
总体思路 :
(借鉴了相似图像搜素的关键技术——哈希算法)将每一张图片人为转换具有0或1规律表达的图像,即将图像按照某个阈值生成对应的指纹字符串。我们最终是通过比较不同图片转后对应位置的指纹字符串,其结果越是趋向于1越相似。
主要实现的步骤如下:
Step 1. 输入图像
Step 2. 进行灰度化 (如果是需要更高精度的图像相似度计算,可以考虑利用原始图)
Step 3. 将输入的图像进行归一化到指定尺寸 例如9*9
Step 4. 等比降低灰度值 (grayValue/N 其中N是正整数,也可以省略)
Step 5. 计算图像平均灰度值average
Step 6. 生成指纹图,将归一化的图像每个位置Img(i,j)与平均灰度值average进行比较,若 Img(I,j)> average,则Img(i,j)=1,否则Img(I,j)=0;
Step 7. 按照一定排列顺序进行两幅图像比较,获得相似度similarity
我设定初始值similarity = 1。
接下来直接上代码:
//第一个函数:计算图片的指纹信息
string CalImgHashValue(IplImage* src)
{
int N = 5; //简化常数,人为设定
int graySum;
string resStr(81,'\0');
uchar* pData;
IplImage* image = cvCreateImage(cvGetSize(src),src->depth,1);
//step2 : 灰度化
if(src->nChannels == 3)
cvCvtColor(src,image,CV_BGR2GRAY);
else
cvCopy(src,image);
//step 3 : 缩小尺寸 9*9
IplImage* temp = cvCreateImage(cvSize(9,9),image->depth,1);
cvResize(image,temp);
//step 4 : 简化计算量
for(int i=0; i<temp->height; i++)
{
pData =(uchar* )(temp->imageData+i*temp->widthStep);
for(int j=0; j<temp->width;j++)
pData[j]= pData[j]/N;
}
//step 5 : 计算平均灰度值
int count = 0;
for (int row = 0; row< src->iHeight; row++)
{
for (int col = 0; col<= src->iWidth; col++)
{
graySum = graySum + (uchar)ImgGray->imageData[row*src->widthStep + col];
count++;
}
}
int average = graySum/count;
//step 6 : 计算哈希值
int index = 0;
for(int i=0; i<temp->height; i++)
{
pData =(uchar* )(temp->imageData+i*temp->widthStep);
for(int j=0; j<temp->width;j++)
{
if(pData[j]>=average)
resStr[index++]='1';
else
resStr[index++]='0';
}
}
return resStr;
}
//第二个函数:计算两幅图像的相似度
void GetImgSimilarity(string &str1,string &str2,double* similarity)
{
*similarity = 1.0;
for(int i=0;i<64;i++)
{
char c1 = str1[i];
char c2 = str2[i];
if(c1!=c2)
*similarity = *similarity -1.0/64;
}
}
//声明
string CalImgHashValue(IplImage* src); //计算图片的指纹信息
void GetImgSimilarity(string &str1,string &str2); //根据指纹信息计算两幅图像的相似度
//测试程序
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
IplImage* img1 = cvLoadImage("hanshanbuleng1.jpg",1);
IplImage* img2 = cvLoadImage("hanshanbuleng2.jpg",1);
cvShowImage("img1 ",img1 );
cvShowImage("img2 ",img2 );
string imgPrint1 = ImageHashValue(image1);
string imgPrint2 = ImageHashValue(image2);
double similarity = 0;
ImageSimilarity(imgPrint1,imgPrint2,&similarity);
cout<<"The similarity of two img is "<<similarity*100<<"%"<<endl;
if(similarity>=0.9)
cout<<"The two img are extremely similar."<<endl;
else if(similarity>=0.8&&similarity<0.9)
cout<<"The two imag are pretty similar."<<endl;
else if(similarity>=0.7&&similarity<0.8)
cout<<"The two imag are a little similar."<<endl;
else if(similarity<0.7)
cout<<"The two img are not similar."<<endl;
cout<<endl;
cvWaitKey(0);
}