花40分钟写一个-CBIR引擎-代码公开

   浏览网页的时候发现一篇不错的文章"用Python和OpenCV创建一个图片搜索引擎的完整指南 " http://python.jobbole.com/80860/. 作者在浏览自己旅游的照片的时候,发现照片太多了分类不过来,一时技痒写了个分类软件,虽然简单但是有用。关键的是我发现他在原文中使用了半个小时就写出来了。【2022年,现在这里的技术已经过时,应该使用milvus】
       蛮快的嘛,我想。那么我要用多长时间写出来了,毕竟对于CBIR也是研究过的。
       那么立即来做,首先我要找到是图片。我没有那么多旅游图片(汗),但是别人的照片也是可以一样用的。找到了之前专门用于测试CBIR的图片集,大概是这个样子

 

 

 
就是各种奇奇怪 怪 的照片。然后搭建opencv的基本框架。我们python用的不熟,但是c++下面自己是有类库的,所以用起来也不是很复杂
      
 首先是读入所有的图片:
//递归读取目录下全部文件
void getFiles(string path, vector <string > & files,string flag){
     //文件句柄
     long   hFile    =    0;
     //文件信息
     struct _finddata_t fileinfo;
    string p;
     if((hFile  = _findfirst(p.assign(path).append( "\\*").c_str(), &fileinfo))  !=   - 1){
         do{
             //如果是目录,迭代之,如果不是,加入列表
             if((fileinfo.attrib  &  _A_SUBDIR)){
                 if(strcmp(fileinfo.name, ".")  !=  0   &&  strcmp(fileinfo.name, "..")  !=  0  && flag == "r")
                    getFiles( p.assign(path).append( "\\").append(fileinfo.name), files,flag );
            }
             else{
                files.push_back(p.assign(path).append( "\\").append(fileinfo.name) );
            }
        } while(_findnext(hFile,  &fileinfo)   ==  0);
        _findclose(hFile);
    }
}
//递归读取目录下全部图片
void getFiles(string path, vector <Mat > & files,string flag){
    vector <string > fileNames;
    getFiles(path,fileNames,flag);
     for ( int i = 0;i <fileNames.size();i ++){
        Mat tmp  = imread(fileNames[i]);
         if (tmp.rows > 0) //如果是图片
            files.push_back(tmp);
    }
}
//递归读取目录下全部图片和名称
void getFiles(string path, vector <pair <Mat,string >> & files,string flag){
    vector <string > fileNames;
    getFiles(path,fileNames,flag);
     for ( int i = 0;i <fileNames.size();i ++){
        Mat tmp  = imread(fileNames[i]);
         if (tmp.rows > 0){
               pair <Mat,string > apir;
               apir.first  = tmp;
               apir.second  = fileNames[i];
               files.push_back(apir);
        }
    }
}
然后是编写hsv距离,这个参考以前的资料
double GetHsVDistance(Mat src_base,Mat src_test1){
    Mat   hsv_base;
    Mat   hsv_test1;
     ///  Convert  to  HSV
    cvtColor(  src_base,  hsv_base,  COLOR_BGR2HSV  );
    cvtColor(  src_test1,  hsv_test1,  COLOR_BGR2HSV  );
     ///  Using  50  bins  for  hue  and  60  for  saturation
     int  h_bins   =   50;   int  s_bins   =   60;
     int  histSize[]   =  {  h_bins,  s_bins  };
     //  hue  varies  from  0  to  179,  saturation  from  0  to  255
     float  h_ranges[]   =  {   0,   180  };
     float  s_ranges[]   =  {   0,   256  };
     const   float *  ranges[]   =  {  h_ranges,  s_ranges  };
     //  Use  the  o-th  and  1-st  channels
     int  channels[]   =  {   0,   1  };
     ///  Histograms
    MatND  hist_base;
    MatND  hist_test1;
     ///  Calculate  the  histograms  for  the  HSV  images
    calcHist(   &hsv_base,   1,  channels,  Mat(),  hist_base,   2,  histSize,  ranges,   true,   false  );
    normalize(  hist_base,  hist_base,   0,   1,  NORM_MINMAX,   - 1,  Mat()  );
    calcHist(   &hsv_test1,   1,  channels,  Mat(),  hist_test1,   2,  histSize,  ranges,   true,   false  );
    normalize(  hist_test1,  hist_test1,   0,   1,  NORM_MINMAX,   - 1,  Mat()  );
     ///  Apply  the  histogram  comparison  methods
     double  base_test1   =  compareHist(  hist_base,  hist_test1,   0  );
     return base_test1;
}

 

封装成函数。这个函数比原文中作者提出的方法要简单,我偷懒了。
然后就是要编写主函数程序,这个比较麻烦的地方就是要比较出最前面的10 个图片 。我采用比较笨的方法,赶时间嘛:
int _tmain( int argc, _TCHAR * argv[])
{    
    vector <pair <Mat,string >> imagepairs;
    vector < double > dresult;
     double dmax  =  0;
     int imax  =  - 1;
    
     //读入图片
    getFiles( "images",imagepairs);
    Mat src  = imread( "images/0.jpg");
     //距离测算
     for ( int i = 0;i <imagepairs.size();i ++){
         double tmp  = GetHsVDistance(src,imagepairs[i].first);
         if (tmp  == 1)
            tmp  = 0; //不能搞自己
         char cbuf[ 1024];
        sprintf_s(cbuf, "dst/%d.jpg",i);
        dresult.push_back(tmp); //推入vecresult中
    }
     //寻找前10个图片
     for ( int index  =  0;index < 10;index ++){
         for ( int i = 0;i <imagepairs.size();i ++){
             if (dresult[i] >dmax){
                dmax  = dresult[i];
                imax  = i;
            }
        }
         char cbuf[ 1024];
        sprintf_s(cbuf, "dst/%d.jpg",index);
        imwrite(cbuf,imagepairs[imax].first);
        dresult[imax]  =  0; //剔出队列
        dmax  =  0;
        imax  =  - 1;
    }
    printf( "OK");
    waitKey();
     return  0;
}

 

 
 
 
前后花了40-50分钟时间,最后的效果不如作者的效果。主要差距在核心算法上面。看来日常的算法总结重构的确很有价值。
这篇文章先写到这里,最近事多,等到闲下来再进行重构。欢迎大家批评指正。
 

posted on 2022-12-22 14:32  jsxyhelu  阅读(95)  评论(0编辑  收藏  举报

导航