(十二)opencv开发的一点经验

来源:互联网 发布:linux 物理内存管理 编辑:程序博客网 时间:2024/05/16 13:07

学MFC的时候就知道这个事情了,那时候记得老师强调多次,如果写的demo想在人家那里演示一下,一定要选择静态库使用mfc,而不是选择动态链接库否则在人家电脑里没有对应的dll文件,是无法运行起来的。可见老师在这方面吃过亏啊。昨天用OpenCV写了个东西,发过去让人家测试,可人家告诉我:“你这土鳖程序在我这无法运行“,好囧啊。这里把我的解决过程记录一下。希望能对大家遇到类似的问题有所帮助。

首先,介绍一下我的开发环境32bits+winXP+VS2008+OpenCV,他的电脑32bits+Win7+none(他电脑其他开发环境基本没装,是个裸机)。


我程序里用到的库文件包括core、highgui、imgproc、video,用的是debug版本,写的是个控制台程序。所以把相应的dll文件copy过去,分别是opencv_core231d.dll、opencv_highgui231d.dll、opencv_imgproc231d.dll、opencv_video231d.dll(如果是release版本,要copy相应的没有d结尾的动态链接库,下面相应的dll都存在类似的问题)。本以为这样就ok了,第一次传给他,他告诉我运行不了,没有任何提示,用命令行运行,提示应用程序缺少相应的并行配置,百度出来的答案千奇百怪,感觉都没有切中要害。

于是又找了一台装的xp的电脑试验,这次弹出错误是缺少tbb_debug.dll,我忽然想起来我第一次运行程序的时候也是弹出过这个错误。于是根据电脑的配置是32位机,开发环境是vs9,找到对应目录下的tbb_debug.dll文件,copy过去,再试。

这次弹出的错误比较离奇,提示缺少msvcp100d.dll,可是大哥,我用的开发环境是vs2008,对应的文件应该是msvcp90d.dll才对吧(这个问题目前没想出合理解释),不管了,死马当活马医,又去别人电脑copy过来msvcp100d.dll和msvcr100d.dll,再试。

这次弹出缺少msvcp90d.dll了,呵呵,该来的还是会来。这是由于他的电脑没有vs平台运行时的对应dll造成的,网上搜了下解决办法。去C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT目录把Microsoft.VC90.CRT.manifest、msvcm90.dll、msvcp90.dll、msvcr90.dll四个文件都copy过来,又去C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.OPENMP目录下把Microsoft.VC90.OpenMP.manifest、vcomp90.dll两个文件copy过去。

这次总算离胜利比较近了,不报错了,但是视频文件无法打开,感觉还是OpenCV相关的动态链接库没有copy过去,又copy了几个dll,比如opencv_ffmpeg.dll。这次总算可以运行了。oh yeah~~

问题是解决了,不过对于dll文件的理解还是不够深刻,网上还有说是因为运行时库的问题,需要在相关项目设置里把MDD设置为MTD,但我试过,发现不是这个问题。要是能有办法,像MFC那样把相应的dll进行静态编译,都做到exe里面就好了。不知道是我知之甚少,还是OpenCV的程序不行。期待高手指点一二。

感谢大家指导,我把心得又写了一篇http://blog.csdn.net/yang_xian521/article/details/7027190

感谢大家对我博客的支持,昨天写的那个土鳖的bloghttp://blog.csdn.net/yang_xian521/article/details/7022701,为了让自己的程序在别人那里运行起来,竟然加了十余个dll,才搞定,太不方便了。对于我这土鳖的办法,有好心的网友看不下去了,告诉我OpenCV是可以制作静态链接库。我顿时来了兴致,百度之,发现确实有办法,但很多都是老版本的数据结构,还是对cv.lib等等的处理。我这里用2.3版实现了一下,把我的心得分享给大家。

首先用cmake重新生成vs2008的解决方案,之前我都用的编译好的OpenCV,现在用的多了,才知道cmake的妙处。因为是要生成opencv的静态库, 去掉一些无关的选项. 去掉BUILD_NEW_PYTHON_SUPPORT,BUILD_SHARED_LIBS, BUILD_TESTS, 勾选OPENCV_BUILD_3RDPARTY_LIBS, WITH_TBB,WITH_JASPER, WITH_JPEG, WITH_PNG, WITH_TIFF选项,然后点击configure. 提示TBB_INCLUDE_DIR找不到,忽略即可,直接点击configure,配置完成,点击generate,完成后关闭cmake得到解决方案后,打开OpenCV.sln,哇,要不要这么多工程...一个一个来吧。根据OpenCV编译好的动态链接的lib,有calib3d、contrib、core、features2d、flann、gpu、haartraining_engine(这个是静态链接的,不需要重新编译)、highgui、imgproc、legacy、ml、objdetect、ts、video,以上这些工程需要重新编译为静态链接库。打开对应工程的属性,找到下图中的对应项,

把输出目录改为自己设定的目录,把配置类型由动态库(.dll)改为静态库(.lib),把运行时库改为静态。重新生成(ctrl+F7)。得到了我心爱的lib文件,不过也吓了我一跳,每个lib比动态链接的lib要大出几十倍,都10M左右,推荐大家写程序,如果不是做成demo,给别人展示,还是不要用静态链接的好,否则做出来的exe好大啊...

我这里把生成的lib库整理了一下,debug版本的在后缀加了231ds,(s表示静态库),release后缀加上了231s。(由于发现OpenCV有做好的静态lib,我就不上传了)

做好了库之后,准备把lib文件copy到我OpenCV的安装目录下准备使用,才悲催的发现原来这个工作OpenCV早已给我做好,都放在build文件夹下面的对应的staticlib目录中了,但和我自己做出来的lib文件大小不一样(估计是cmake时候的选项选择的不同)。还有一个问题就是悲催的发现OpenCV自带的静态lib文件和动态lib文件命名是相同的,这可如何在附加依赖项中选择填写啊,还是用我自己写的后缀名不同的库做测试吧(后来发现只有在配置的vc++目录里的库文件目录中添加staticlib路径,然后把该路径的顺序调整到lib路径前,就可以优先调用staticlib了)。我在我原来的程序里测试了一下,还是不能编译通过,很让我恼火,求助了高人发现是附加依赖库并没有添加完全,找到对应的3rdparty\lib文件夹下面的zlibd.lib、libjasperd.lib、libjpegd.lib、libpngd.lib、libtiffd.lib。把这几个文件copy到安装目录下,并在vs2008中配置好,这次有些可以编译通过了,但涉及到video的highgui.lib还是不能通过。查了一下,是没有调用系统库文件vfw32.lib和videoInput.lib(这个lib可以在cmake时选择是否使用),新的gui还调用了滑杆控件,还需要添加comctl32.lib这个lib,把这两个库链接时添上即可。总结一下,就是需要多添加comctl32.lib vfw32.lib zlibd.lib libjasperd.lib libjpegd.lib libpngd.lib libtiffd.lib opencv_core231d.lib opencv_objdetect231d.lib opencv_highgui231d.lib opencv_imgproc231d.lib,对应的release版本就把带d后缀的去掉即可。

最后再补充一下上一讲没说清楚的运行时库的问题,我的程序想在朋友电脑(没有vs开发环境)上运行,就需要运行时库的支持。除了我上一讲比较土鳖的办法(把运行时库的dll全部copy过去),还有一种办法就是在工程的属性设置里把c++ -->代码生成 --> 运行时库的对应项选好。这里介绍一下运行库(Runtime Library)。运行库是最基本的库,配合C++的语法及操作系统实现了一些基本的功能,如内存操作(new/delete等)等。可以说运行库是任何 程序,库的基础。在VC(2005以上)中有四种运行库:Multi-threaded、Multi-threaded-Debug、Multi- threaded-dll、Multi-threaded-debug-dll:前两个为一组,是静态类型库,提供的函数会被链接到最后的程序中,其中两 者的区别就在于一个带些调试用的信息及检查代码;后两个为一组,是动态库,最后会以动态链接库的形式(如在VC2008中为MSVCR90.dll或 MSVCR90D.dll),提供函数给程序调用。这里把MDD改为MTD(不然好像编译也无法通过)。就不需要copy过去多余的dll文件啦。

至此,只需要copy过去一个tbb_debug.dll,我的程序就能正常运行啦,我想通过cmake重新得到不嵌入tbb的opencv的lib,应该就能解决,但对于tbb是个啥东西还不懂,还是学精了再拿出来分享吧。路漫漫啊,感谢大家的阅读和支持。

之前介绍过一篇利用级联分类器对目标进行检测的文章http://blog.csdn.net/yang_xian521/article/details/6973667,用的就是haar特征。发现OpenCV自带的库里的haar特征只有人脸、人脸的器官和人的身体,最近又想玩一个人手的检测,之前用颜色特征做的,感觉很不靠谱,这次用haar特征再试一次。这就需要用haartraining这个工具训练自己的手。先介绍一些预备知识,推荐个网址http://www.opencv.org.cn/index.php/%E7%89%B9%E5%BE%81%E6%A3%80%E6%B5%8B%E4%B8%93%E9%A2%98,读完相信对haar特征来龙去脉有个认识了,具体怎么使用,推荐看看这个http://note.sonots.com/SciSoftware/haartraining/document.html,再推荐这个网址http://note.sonots.com/SciSoftware/haartraining.html,都是英文哦,我就是按照这个英文介绍的教程训练自己的手分类器的。后来发现有人已经做了这个教程的翻译http://blog.csdn.net/onlyyouandme/article/details/4722160和http://blog.csdn.net/onlyyouandme/article/details/4722202(还是看英文原文比较详细),我也参考了这个http://hi.baidu.com/andyzcj/blog/item/3b9575fc63c3201f09244d9a.html,都贴上来以备以后再训练时学习需要。训练过程相当痛苦漫长,累死我心爱的PC了。由于训练数据不是我的个人财富,所以不便上传,这里把我download的一个老外训练的拳头的手势分类器(拳头在英文手语里表示字母A)作为实验来源。

资料还是得看啊,又读了经典文献《Robust Real-Time Face Detection》,不愿意读原文的朋友可以看看http://blog.csdn.net/hqw7286/article/details/5556767,作者把文中的要点基本也都总结出来了。OpenCV的实现过程也是在这篇文章的基础上,后来又不断完善的。

自己跟踪了一下代码,发现OpenCV的级联分类器的分为老版本和新版本,所有的haar级联分类器都是老版本的,只有一个lbp分类器是新版本的,而老版本的级联分类器的训练检测还是用老版本的数据结构来写的(让我很不爽,真想变得强大起来,用新数据结构写一下),为了这个新版本的级联分类器,多添加了大量的代码,可是用haartraining训练出来的分类器也是老版本的,该如何添加新版本的级联分类器啊,期待下一版本的OpenCV能够用新版本的haar级联分类器替代老版本。从这段代码中,我也深深体会到版本兼容的辛酸了。再这里也默默祝OpenCV越来越好,更规整,更强大。

最后上传一下效果图,再上传一段录制的视频(上镜了,很挫)http://v.youku.com/v_show/id_XMzI4NTQ1OTQ4.html和代码下载地址http://download.csdn.net/detail/yang_xian521/3873942

之前做了haartraining的东西,感觉到OpenCV里面实现的东西还不是很好,这个老版本的haartraining的东西在新版本仍然是用老版本的函数来实现的,让我很不爽。于是好期待下一版本的到来,索性研究一下OpenCV路在何方,由于才接触OpenCV不久,就研究它的路在何方有些自不量力,但还是搜集了不少的资料,把我搜集的东西和大家分享一下,有说的不对的,欢迎大家都指点出来~~

首先说说OpenCV接下来的动作,然后再分析分析OpenCV如今还欠缺的东东

一、 Coming Soon
1.听说OpenCV要成为Khronos Group的成员啦,这真是一个振奋的消息,这个组织致力于发展开放标准的应用程序接口 API,大名鼎鼎的OpenGL也是这个组织的成员。成为该组织的成员,我想更有利于OpenCV做出标准的APIs,也更好的实现对其的硬件加速。


2.现在OpenCV已经实现了对Android的支持,随着移动设备的应用的越来越广泛,下一步OpenCV也要实现对iPhone的支持

3.增强对GPU的支持,GPU现在发展速度很快,OpenCV也要跟上脚步哈

4.也准备对FPGA进行一些支持,以后搞硬件开发的也许也能用到OpenCV,也许几年后,你用到的视觉芯片里面就有OpenCV的东西呢

5.ecto flow 图形交互也要加强。这点我理解的不是很好,目前OpenCV的图形交互确实做的不够好,对科研人员常用的MFC(虽然古老,但长青啊)支持越来越少,现在对Qt的支持倒是还可以,但我找了半天,也没明白这个ecto flow 图形交互是个什么东西,期待OpenCV的交互越做越好~~只能默默期待了。

6.OpenCV终于要做新网站了,不要再寄生在source forge和wiki上了,很期待它的新主页

7.更多的文档和更多的教程永远是我们这些学习人员心中的痛,捧着《learning OpenCV》总让我感觉吃不饱啊,期待新的reference manual和tutorials赶快出炉,之前读到一些感兴趣的地方就发现写着TBD(to be discuss),真让人心里不好受,看看人家微软的MSDN,难道开源的东西维护文档就不能做的那么好么,这是我们所有使用OpenCV人肩上的重担啊。

8.可能也会做更多的训练好的分类器,将来data\文件夹下面将有更多的xml可以利用,值得期待

9.接下来的一些加强应该是现在比较火的一些东西,对人体的2D和3D的跟踪,基于纹理的物体检测,Winner take all engine(不理解啊。。。),linemod(同样不理解-_-|||),三维模型的捕获,2维条形码,3维的训练和评估,相信以后用OpenCV做开发会越来越方便~~

二、 Missing Now
1.intrinsic image是透视图么?难道以后用OpenCV能看到人的透视图,我邪恶了。。。

2.对光线的检测一直是图像处理方面的一个难题,目前解决的还不好

3.颜色的不变性也是个问题

4.SFM(交叉矩阵),是不是又对Mat这个数据结构不满意了,以后可能有更好的数据结构出现,真是精益求精

5.vSLAM也没有支持,看来OpenCV对机器人的支持也有个想法,未来机器人定位的开发也许会用到更多的OpenCV

6.AR的支持也不好,这对做增强现实的朋友也许是个痛,希望有更多的API可以给开发者调用

7.还有就是对硬件的支持还不够完美,要是能对ARM平台也有类似IPP、TBB的优化就好了;要是能对GPU加速能实现自动化就好了;要是。。。。好啦,不做梦啦

就说这些吧,很多都是搜集的东西,自己的水平距离全部理解这些还远着呢,先随便说说,有说错的,请大家见谅,欢迎留言,看了觉得我胡说八道,颠倒是非的,您大可提出来。您的关注是我进步的动力,您的指导是我前进的方向!

之前介绍了Qt+OpenCV的图形界面设计http://blog.csdn.net/yang_xian521/article/details/6968012,那篇里面只是读取了图片,这次再略进一步,再实现一个摄像头视频的读取。

再介绍一下我的开发环境Qt4.7.4+OpenCV2.3.1+VS2008,其实很简单,先在自己的QMainWindow子类里面声明如下变量:

view plain
public:  
    camCapture(QWidget *parent = 0, Qt::WFlags flags = 0);  
    ~camCapture();  
protected:  
    void paintEvent(QPaintEvent * e);  
  
private:  
    Ui::camCaptureClass ui;  
    cv::Mat frame;  
    cv::VideoCapture capture;  
    QImage *image;  
    QTimer *timer;  
  
private slots:  
    void nextFrame();  

paintEvent函数是重载的,目的是为了更新绘图,在其定义中添加:

view plain
void camCapture::paintEvent(QPaintEvent * e)  
{  
    // 更新图像  
    QPainter painter(this);  
    painter.drawImage(QPoint(0, 12), *image);  
}  

camCapture的构造函数里面添加如下初始化代码:

view plain
// 初始化处理,建立QImage和frame的关联,开启定时器  
    capture.open(-1);  
    if (capture.isOpened())  
    {  
        capture >> frame;  
        if (!frame.empty())  
        {  
            cv::cvtColor(frame, frame, CV_BGR2RGB);  
            cv::flip(frame, frame, 1);  
            image = new QImage((const unsigned char*)(frame.data), frame.cols, frame.rows, QImage::Format_RGB888);  
            timer = new QTimer(this);  
            timer->setInterval(30);  
            connect(timer, SIGNAL(timeout()), this, SLOT(nextFrame()));  
            timer->start();  
        }  
    }  

析构函数里释放timer和image变量。

nextFrame函数实现数据的更新:

view plain
// 更新数据  
    capture >> frame;  
    if (!frame.empty())  
    {  
        cv::cvtColor(frame, frame, CV_BGR2RGB);  
        cv::flip(frame, frame, 1);  
        this->update();  
    }  

这里我又想起来了我当时做图片读取的时候把参数CV_BGR2RGB、Format_RGB888改为了CV_BGR2RGBA、Format_RGB32,但这次试验发现那组参数可能只对我试验的图片有效,对视频还是CV_BGR2RGB、Format_RGB888这组参数是能用的。

还有一点很不爽,就是添加函数nextFrame和重载paintEvent函数都找不到向导,都是我自己敲进去的,可能是我的开发环境VS对Qt工程的支持不够霸气,以后可能要果断使用QtCreator了。我是Qt方面的真菜鸟,要是有经验的朋友可以给我说说怎么在VS环境里找到添加Qt事件的向导。万分感谢。

欢迎大家下载http://download.csdn.net/detail/yang_xian521/3882970

原创粉丝点击