1. 程式人生 > >圖片相似度計算

圖片相似度計算

今天自己寫了一個簡單的計算圖相似度的演算法,借鑑了雜湊演算法思想進行編寫,在此分享給大家!

總體思路 :

(借鑑了相似影象搜素的關鍵技術——雜湊演算法)將每一張圖片人為轉換具有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);
}