一種基於特徵點匹配的圖像檢索方法的opencv實現

由於最初這個方法是用qt界面的形式呈現了,沒有平常見到的main函數執行圖像檢索的那樣,我稍微做了下整理,提供出一個c++接口interface()可供調用。註釋還比較少,後面有時間補上。

#ifndef IMAGERETRIVAL
#define IMAGERETRIVAL

//#include <cxcore.h>
#include <opencv2\features2d\features2d.hpp>
#include <opencv2\calib3d\calib3d.hpp>
#include <opencv2\contrib\contrib.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <highgui.h>
#include <iostream>
#include <map>
#include <io.h>
using namespace std ;
using namespace cv;

#define HessianThreshold 400
#define MAX_Image_Num 1000
#define MIN_Image_Similar_Threshold 0.001

struct matDescToImgfile{
    int i_begin_index ;
    int i_end_index ;
    string s_imge_filename ;
};
const string trainFileType = "jpg"; //  "*" represent any file type.


//////////////////////////////////////////////////////////////////////////
//從目錄中讀取文件名列表
int readDirFile(const string dirName, const string fileType , vector<string> &allFilename)
{
    int fileNum = 0 ;
    _finddata_t onefile ;

    long lFile ;
    string dirName_FileType = dirName + "\\*."+fileType;

    lFile = _findfirst(dirName_FileType.c_str() , &onefile) ;
    if (lFile == -1l ) //on such file, return -1l (long type)
    {
        cout << "can`t find the file"<<endl;
        return fileNum ;
    }
    else
    {
        //cout <<"the files of the folder:"<<endl ;
        do
        {
            //cout<<onefile.name <<endl ;
            allFilename.push_back(onefile.name) ;
            fileNum ++ ;
        } while (_findnext(lFile , &onefile) == 0);

    }
    _findclose(lFile) ;

    return fileNum ;
}
//////////////////////////////////////////////////////////////////////////
void createDetectorDescriptor(const string trainDirName,vector<string> trainAllFileName,
    Mat& matTotalDesc,	vector<matDescToImgfile>& vec_Desc_Imgfile)
{
    //創建特徵點提取器
    cv::SurfFeatureDetector*     m_pDector    = new cv::SurfFeatureDetector(HessianThreshold); //HessianThreshold
    SurfDescriptorExtractor* m_pExtractor = new SurfDescriptorExtractor;

    //讀取train中圖片
    //提取特徵點及描述符
    //描述符提取
    Mat  ImgMat ;
    vector<KeyPoint> veckps;
    Mat matDesc;

    matDescToImgfile one_img_log ;
    int img_num = 0 ;

    vector<string>::iterator imageName ;

    for (imageName = trainAllFileName.begin() ; imageName != trainAllFileName.end() ; imageName++)
    {
        veckps.clear();
        matDesc.release();
        ImgMat.release();

        //cout<<trainDirName+"\\"+*imageName <<endl ;
        ImgMat = imread(trainDirName+"\\"+*imageName,CV_LOAD_IMAGE_ANYCOLOR) ; //CV_LOAD_IMAGE_ANYDEPTH

        m_pDector->detect(ImgMat,veckps);
        if(veckps.size() == 0)
        {
            return ;
        }

        m_pExtractor->compute(ImgMat,veckps,matDesc);

        matTotalDesc.push_back(matDesc) ;//集中所有matDesc形成matTotalDesc


        if (img_num == 0)
        {
            one_img_log.i_begin_index = 0 ;
            one_img_log.i_end_index = matDesc.rows-1 ;
            one_img_log.s_imge_filename = trainDirName+"\\"+*imageName ;
        }
        else {
            one_img_log.i_begin_index = one_img_log.i_end_index + 1;
            one_img_log.i_end_index = one_img_log.i_begin_index + matDesc.rows-1 ;
            one_img_log.s_imge_filename = trainDirName+"\\"+*imageName ;
        }
        img_num++;
        vec_Desc_Imgfile.push_back(one_img_log) ;

    }
    delete(m_pDector);
    delete(m_pExtractor);
}
vector<string> GetImageFromKNN(vector<matDescToImgfile> Desc_Imgfile ,cv::Mat Indices ,
    const int Img_Num ,const double Max_Threshold,int rankNum)
{
    int flag_count[200]  ={0};
    //cout << "Img_Num=" << Img_Num << endl;
    vector<matDescToImgfile>::iterator oneDescLog ;
    MatIterator_ <int> it_indice  ;
    int key ;

    for (it_indice = Indices.begin<int>() ; it_indice!= Indices.end<int>() ; it_indice++)
    {
        key = *it_indice ;
        int i = 0 ;

        for (oneDescLog = Desc_Imgfile.begin() ; oneDescLog!=Desc_Imgfile.end(); oneDescLog++ , i ++)
        {
            if (key >= oneDescLog->i_begin_index && key <= oneDescLog->i_end_index)
            {
                flag_count[i] ++ ;//flag ++
				break;
            }
        }

    }//找到indices中相似描述符屬於哪個區間
    multimap<int,int> result;
    for(int j=0;j<Img_Num;j++){
        result.insert(make_pair(flag_count[j],j));
        //result[flag_count[j]] = j;
    }

    float max_flag = 0 ;
    int count_num =-1;
    vector<int> index;
    vector<string> resultStr;
    for (multimap<int, int>::reverse_iterator iter = result.rbegin();iter != result.rend();++iter){

        index.push_back(iter->second);
      }

    assert(rankNum <= Img_Num);
    for (int i=0;i<rankNum;i++){
        resultStr.push_back(Desc_Imgfile.at(index[i]).s_imge_filename);
        //cout << Desc_Imgfile.at(index[i]).s_imge_filename << endl;
    }
    return resultStr;
    /*for (int j = 0 ; j < Img_Num ; j++ )
    {
        if (max_flag < flag_count[j]/float (Indices.rows))
        {
            max_flag = flag_count[j]/float (Indices.rows) ;
            count_num = j ;
        }
    }
    //cout<<"max similarity ratio \t"<<max_flag<<endl;
    if (max_flag > Max_Threshold)
    {
        return Desc_Imgfile.at(count_num).s_imge_filename ;
    }
    else
        return "";*/

}
//////////////////////////////////////////////////////////////////////////
vector<string> OneImageRetrival(cv::flann::Index& m_index, const string query_image_name ,
    vector<matDescToImgfile>& vec_Desc_Imgfile,int kNum)
{
    //創建特徵點提取器
    SurfFeatureDetector*     m_pDector    = new SurfFeatureDetector(HessianThreshold); //HessianThreshold
    SurfDescriptorExtractor* m_pExtractor = new SurfDescriptorExtractor;

    Mat QueryMat ;
    vector<KeyPoint> QueryVecKP ;
    Mat QueryMatDesc ;

    QueryMat = imread(query_image_name,CV_LOAD_IMAGE_ANYCOLOR);
	//QueryMat.resize(256,256);
	



    m_pDector->detect(QueryMat,QueryVecKP);

    m_pExtractor->compute(QueryMat,QueryVecKP,QueryMatDesc);

    cv::Mat indices(QueryMatDesc.rows, 1, CV_32S);
    cv::Mat dists(QueryMatDesc.rows  , 1, CV_32F);

    m_index.knnSearch(QueryMatDesc, indices, dists, 10, cv::flann::SearchParams(512) );

    vector<string> s_the_result_filename = GetImageFromKNN(vec_Desc_Imgfile , indices , vec_Desc_Imgfile.size() ,MIN_Image_Similar_Threshold,kNum) ;


    delete(m_pDector);
    delete(m_pExtractor);
    return s_the_result_filename;
}
//////////////////////////////////////////////////////////////////////////
//filename是想要檢索的那個圖片的包括絕對路徑的名字,trainDirName是檢索圖像庫的絕對路徑,kNum是想要檢索前多少個相似的圖片,這個值一定要小於圖片的數量
vector<string> interface(string filename,string trainDirName,int kNum)
{

    //////////////////////////////////////////////////////////////////////////
    //cout<<"\n###step 1 --read the train file :"<<endl ;
    vector<string> trainAllFileName ;

    int readFileStatus = readDirFile(trainDirName , trainFileType,trainAllFileName) ;


    //////////////////////////////////////////////////////////////////////////

    Mat matTotalDesc ;
    vector<matDescToImgfile> vec_Desc_Imgfile ;



    createDetectorDescriptor(trainDirName,trainAllFileName , matTotalDesc ,vec_Desc_Imgfile) ;

    //建立隨機kd-tree

    cv::flann::Index m_index(matTotalDesc, cv::flann::KDTreeIndexParams(4));


    vector<string> resultFIlename = OneImageRetrival(m_index, filename , vec_Desc_Imgfile,kNum) ;
    return resultFIlename;
}
#endif // IMAGERETRIVAL

效果展示如下圖所示:



轉載請註明地址:http://blog.csdn.net/xbcreal/article/details/70313907

發佈了51 篇原創文章 · 獲贊 90 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章