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


          浏览网页的时候发现一篇不错的文章"用Python和OpenCV创建一个图片搜索引擎的完整指南"http://python.jobbole.com/80860/.作者在浏览自己旅游的照片的时候,发现照片太多了分类不过来,一时技痒写了个分类软件,虽然简单但是有用。关键的是我发现他在原文中使用了半个小时就写出来了。
           蛮快的嘛,我想。那么我要用多长时间写出来了,毕竟对于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分钟时间,最后的效果不如作者的效果。主要差距在核心算法上面。看来日常的算法总结重构的确很有价值。
    这篇文章先写到这里,最近事多,等到闲下来再进行重构。欢迎大家批评指正。
     





  • 相关阅读:
    Spring 注解大全
    sql相关
    深入理解Java虚拟机 自己编译JDK
    MarkDown语法 学习笔记 效果源码对照
    学习
    【转】Java方向如何准备BAT技术面试答案(汇总版)
    Java (PO,VO,DAO,BO,POJO,DTO) 几种对象解释
    Python实现脚本锁功能,同时只能执行一个脚本
    java 内存管理 —— 《Hotspot内存管理白皮书》
    vue子组件实时获取父组件传来的值
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/5174346.html
Copyright © 2020-2023  润新知