[项目实战派]花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分钟时间,最后的效果不如作者的效果。主要差距在核心算法上面。看来日常的算法总结重构的确很有价值。

这篇文章先写到这里,最近事多,等到闲下来再进行重构。欢迎大家批评指正。

来自为知笔记(Wiz)

时间: 2024-10-16 20:01:40

[项目实战派]花40分钟写一个-CBIR引擎-代码公开的相关文章

像阿超那样,花20分钟写一个能自动生成小心四则运算题目的 “软件”,要求:除了整数以外,还要支持真分数的四则运算。 和同学们比较一下各自程序的功能,实现方法的异同,等等

package chapter; public class szys {    public static void main(String[] args)    { print30Questions();    }        private static void print30Questions()     {        //说明:打印30道题函数,把接收到的题目字符串按照指定格式输出.        for (int i = 0; i < 10; i++)        {    

像阿超那样,花20分钟写一个能自动生成小学四则运算题目的 “软件”,要求:除了整数以外,还要支持真分数的四则运算。

public class c30questions { public static void main(String[] args) { print30Questions(); } private static void print30Questions() { //说明:打印30道题函数,把接收到的题目字符串按照指定格式输出. for (int i = 0; i < 10; i++) { System.out.print( i+1 ); System.out.print("."

[blog 项目实战派]压板识别项目分析

压板识别项目 零.相关说明: 首先进行一下相关说明.在"jsxyhelu.cnblogs.com/项目实战派"栏目里面出现的需求.图片和其他资源,都是我在浏览威客网站.论坛等网站的时候通过正规渠道获得的真实需求.个人觉得比较感兴趣,但是由于时间或者工作的冲突自己没有去接这些项目.但是由于这些需求都很有实现价值,所以过了一段时间,仍然拿出来练一练手,并且实现了核心模块.希望能够给浏览者一些启发.如果你认为这些图片和资源放在这里不合适,请及时联系我([email protected]),我

[blog 项目实战派]csharp通过dll调用opencv函数

[blog 项目实战派]opencv通过dll调用matlab函数,图片作为参数 前文介绍了如何“csharp通过dll调用opencv函数,图片作为参数”.而在实际的代码编写过程中,很多时候想把已经写好的matlab函数融合进去,但是依然是将图片作为参数传递比较成为问题.这里我经过一段时间的研究解决了这个问题(目前只解决了灰度图片下的图片传递问题).这个问题包含几个难点,一个是mxmatrix的使用,一个是matlab和opencv对于图片的格式处理是不一样的. 本次这个项目,是opencv通

编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(四)结语

四则运算编译器,虽然说功能很简单,只能编译四则运算表达式.但是编译原理前端部分几乎都有涉及,词法分析,语法分析,还有代码生成. 再复杂的编译器.再简单的编译器,功能上是差不多的,只是复杂的编译器实现上会更困难. 这个系列的文章是为了帮助你入门,在这个基础上再去看编译原理相关书籍,不至于打瞌睡. 如果你对编译原理很有兴趣,并且想更深一步的学习,在这里强烈推荐你看一本书--我心目中的神书--<计算机系统要素-从零开始构建现代计算机>. 这本书神在哪? 神在它通俗易懂,对小白足够友好,但又不过分肤浅

【项目实战派】图像处理项目硬件选型

[项目实战派]图像处理项目的硬件平台选型 一直以来我都对嵌入式系统比较感兴趣,因为感到图像处理最终还是要走向便携式.移动化的.这里讲自己对图像处理项目的硬件平台选型这块的想法进行交流,欢迎交流.批评. 一.典型图像处理系统构建 ①相机与镜头--这部分属于成像器件,通常的视觉系统都是由一套或者多套这样的成像系统组成,如果有多路相机,可能由图像卡切换来获取图像数据,也可能由同步控制同时获取多相机通道的数据.根据应用的需要相机可能是输出标准的单色视频(RS-170/CCIR).复合信号(Y/C).RG

[blog 项目实战派]钢管识别项目2

钢管识别项目2 零.相关说明: 首先进行一下相关说明.在"jsxyhelu.cnblogs.com/项目实战派"栏目里面出现的需求.图片和其他资源,都是我在浏览威客网站.论坛等网站的时候通过正规渠道获得的真实需求.个人觉得比较感兴趣,但是由于时间或者工作的冲突自己没有去接这些项目.但是由于这些需求都很有实现价值,所以过了一段时间,仍然拿出来练一练手,并且实现了核心模块.希望能够给浏览者一些启发.如果你认为这些图片和资源放在这里不合适,请及时联系我([email protected]),

[blog 项目实战派]钢管识别项目1

钢管识别项目1 零.相关说明: 首先进行一下相关说明.在"jsxyhelu.cnblogs.com/项目实战派"栏目里面出现的需求.图片和其他资源,都是我在浏览威客网站.论坛等网站的时候通过正规渠道获得的真实需求.个人觉得比较感兴趣,但是由于时间或者工作的冲突自己没有去接这些项目.但是由于这些需求都很有实现价值,所以过了一段时间,仍然拿出来练一练手,并且实现了核心模块.希望能够给浏览者一些启发.如果你认为这些图片和资源放在这里不合适,请及时联系我([email protected]),

【项目实战派】触摸屏程序设计要点

[项目实战派]触摸屏程序设计要点            触摸屏作为一种更为直接的人机交互方式,现在广泛运用于智能手机.工业控制.场景展示等许多场合.作为程序员,如何理解触摸屏程序设计?如何做好的触摸屏程序设计?现在已经有的资源包括那些?借着项目牵引,我对这个问题进行一定探索,经验有限,欢迎批评交流. 一.如何理解触摸屏程序设计 操作系统层面已经实现了基础功能,基于触摸屏的界面,从本质上来说和普通的GuI界面是没有区别的.程序的界面设计需要服务于程序的功能,为客户提供直观.易用.体验效果较好的界面