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

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





目前方向:图像拼接融合、图像识别 联系方式:jsxyhelu@foxmail.com
目录
相关文章
|
10天前
|
JavaScript 前端开发 开发工具
如何参与开源项目以及贡献代码的流程和注意事项(2024年11月保姆级教程)
本文详细介绍了如何参与开源项目及贡献代码的流程和注意事项,包括选择项目、fork仓库、克隆到本地、阅读贡献指南、提交代码、创建Pull Request等步骤,并强调了沟通礼仪、代码质量的重要性,适合初学者参考学习。
如何参与开源项目以及贡献代码的流程和注意事项(2024年11月保姆级教程)
|
7月前
|
人工智能 JavaScript 前端开发
转行做 IT 多数在 30 岁+、43%程序员每天一半时间不在编码,最新开发者生态系统现状报告发布!...
为了洞察开发者及其技术的最新趋势,行业中领头的 Java IDE IntelliJ IDEA、Kotlin 编程语言背后的软件工具开发公司 JetBrains 在调研了来自全球 26,348 位开发者后,最新发布了《2023 开发者生态系统现状》(https://www.jetbrains.com/zh-cn/lp/devecosystem-2023/)。
|
自然语言处理 API Python
除庄周梦蝶外,庄子还讲过哪些梦你知道吗?新故事引出新版本——
除庄周梦蝶外,庄子还讲过哪些梦你知道吗?新故事引出新版本——
177 0
|
XML Java 数据库连接
工作几年了,原来我只用了数据校验的皮毛~
前言 什么是 JSR-303? 添加依赖 内嵌的注解有哪些? 如何使用? 简单校验 分组校验 嵌套校验 如何接收校验结果? BindingResult 接收 全局异常捕捉 spring-boot-starter-validation做了什么? 如何自定义校验? 自定义校验注解 自定义校验器 演示 总结
|
Rust
GitHub 项目持续本地化,交给它来做,准没错!
不知道你们有没有在 GitHub 上看到过一些项目,它的一份项目文档被翻译成了多国语言的版本。
249 0
GitHub 项目持续本地化,交给它来做,准没错!
|
SQL 存储 分布式计算
“开源”vs“商业”,差别到底有多大?这篇测试一目了然
来自用户的声音… 开源就能搞定,还要选商业方案吗? 我是小白用户,开源方案上手快吗? 性能有极致要求,开源能满足吗? 追求性价比,哪种方案更适合我? 我对MySQL很熟悉,数据分析场景适合吗? 上述问题如何解?看阿里云帮你对比分析!
15147 0
“开源”vs“商业”,差别到底有多大?这篇测试一目了然
|
程序员
程序员总数3W+,阿里巴巴首次公开2018代码数据报告
扫描上述二维码或点我直达 免费领!
14062 0
|
存储 Rust 安全
历时四年,Dropbox 用 Rust 重写同步引擎核心代码
过去四年,我们一直在努力重构 Dropbox 桌面客户端同步引擎,这是 Dropbox 文件夹背后的重要技术,也是 Dropbox 最古老、最重要的代码之一。经过四年努力,我们已经向所有 Dropbox 用户发布了用 Rust 写的新同步引擎(代号为 “Nucleus” )。