社区应用 最新帖子 精华区 社区服务 会员列表 统计排行 银行

  • 80006阅读
  • 55回复

OpenCV(开源计算机视觉库介绍)

级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
OpenCV是一个用于图像处理、分析、机器视觉方面的开源函数库.
      无论你是做科学研究,还是商业应用,opencv都可以作为你理想的工具库,因为,对于这两者,它完全是免费的。

该库采用C及C++语言编写,可以在windows, linux, mac OSX系统上面运行。该库的所有代码都经过优化,计算效率很高,因为,它更专注于设计成为一种用于实时系统的开源库。opencv采用C语言进行优化,而且,在多核机器上面,其运行速度会更快。它的一个目标是提供友好的机器视觉接口函数,从而使得复杂的机器视觉产品可以加速面世。该库包含了横跨工业产品检测、医学图像处理、安防、用户界面、摄像头标定、三维成像、机器视觉等领域的超过500个接口函数。

      同时,由于计算机视觉与机器学习密不可分,该库也包含了比较常用的一些机器学习算法。或许,很多人知道,图像识别、机器视觉在安防领域有所应用。但,很少有人知道,在航拍图片、街道图片(例如google street view)中,要严重依赖于机器视觉的摄像头标定、图像融合等技术。

      近年来,在入侵检测、特定目标跟踪、目标检测、人脸检测、人脸识别、人脸跟踪等领域,opencv可谓大显身手,而这些,仅仅是其应用的冰山一角。

      如今,来自世界各地的各大公司、科研机构的研究人员,共同维护支持着opencv的开源库开发。这些公司和机构包括:微软,IBM,索尼、西门子、google、intel、斯坦福、MIT、CMU、剑桥。。。



尽管之前写过一篇关于OpenCV的介绍(http://blog.csdn.net/carson2005/article/details/5822149
),但依然有朋友对其不甚了解。所以,经常能碰到有人问我诸如以下一些问题:OpenCV能不能实现人脸识别?OpenCV有没有车辆检测的API?OpenCV有没有三维重建的函数?面对这样的问题,我也很困惑。到底该如何给他们解释,才能让它们明白,OpenCV确实很强大,但还没有他们想象中的那么强大。其实,OpenCV的全称,是Open source Computer Vision Library,开放源代码计算机视觉库。也就是说,它是一套关于计算机视觉的开放源代码的API函数库。这也就意味着,(1)不管是科学研究,还是商业应用,都可以利用它来作开发;(2)所有API函数的源代码都是公开的,你可以看到其内部实现的程序步骤;(3)你可以修改OpenCV的源代码,编译生成你需要的特定API函数。但是,作为一个库,它所提供的,仅仅是一些常用的,经典的,大众化的算法的API。一个典型的计算机视觉算法,应该包含以下一些步骤:(1)数据获取(对OpenCV来说,就是图片);(2)预处理;(3)特征提取;(4)特征选择;(5)分类器设计与训练;(6)分类判别;而OpenCV对这六个部分,分别(记住这个词)提供了API。下面我分别就这六个部分来进行一些常见问题的解释。

        对于数据获取,计算机视觉领域的数据,无非就是图片和视频两种。图片,有bmp,jpg,png,tiff....各种压缩和非压缩格式。所以,对压缩格式的图片而言,OpenCV内部必然包含了对应的解压函数(一般都是包含了开源的图片解压函数库,例如,对于jpg压缩格式而言,就包含了libjpg开源库)。而对于视频而言,常见的有.rmvb,.avi,.asf等格式,不同的格式,代表着不同的压缩方法(对于AVI格式,尽管都是avi格式,但内部的压缩算法仍然不相同。原因请见我的令一篇博客:http://blog.csdn.net/carson2005/article/details/6314089),也就需要对应的解压方法来解压。尽管OpenCV提供了一些读写视频文件的API,但是,它也仅仅是一个接口而已,其内部,依然需要调用想用的视频编解码器的API来进行解码。常用的视频编解码器有:xvid,ffmpeg等。也就是说,如果你想利用OpenCV来进行视频读写之类的操作,是需要安装此类视频编解码器的。安装了相应的视频解码器之后,你就可以调用OpenCV的视频相关API来进行视频文件的读取了,当然,视频文件被解码之后,变成了一张一张的图片,然后才能被OpenCV所处理。另外,还有一种情况,就是数据来自于相机,包括数字相机和模拟相机。不管是哪种相机,你都要想办法获取到相机发送给PC的图片数据(在内存里面可能是jpg格式,也可能是bmp格式),如果,你在PC内存中接收到的是相机发送过来的jpg压缩格式,还需要进行图片数据的内存解压。关于相机和OpenCV的这部分内容,请见我另一篇博客:
http://blog.csdn.net/carson2005/article/details/6243476
        对于预处理,一般就是去除或者降低噪声,光照归一化,亮度归一化,模糊化,锐化,膨胀,腐蚀、开闭等这些操作(详见,冈萨雷斯,《数字图像处理》一书)。而对于这些操作,OpenCV分别(又提到这个词了)提供了相应API函数。而光照的预处理,OpenCV提供了一个直方图均衡化的API,后续可能会提供一些gammar矫正之类的函数。
        对于特征提取,个人认为,可以算是整个计算机视觉系统中最为复杂也最难的部分(纯属个人意见,如若不同,请保留),到底什么是特征,该如何来理解这个看似简单确又包罗万象的名词呢?其实,要想仔细解释,还真的花费很多时间(有兴趣的可以看看,Richard O.Duda(著),李宏东(译),《模式识别》,机械工业出版社)。简单点说,特征,就是一个可以将若干个类别可以尽量分开的一种描述。举例来说,如果你要进行男人和女人的分类,显然,用“身高和体重”这一描述来衡量,是可以的,但是,这两者没有“胸部大小”这一描述更加准确,而“胸部大小”这一描述,又没有“喉结的有无”这一描述更准确。很显然,“身高和体重”,“胸部大小”,“喉结的有无”,这三种描述,都可以用来进行男人和女人的分类,只不过,它们对事物的描述的准确(或者说全面)程度是不同的,而诸如此类的描述,有一个更加专业,叫做“特征”。OpenCV里面,提供了一些特征描述的API,比如,对于人脸检测而言,它提供了haar特征的API,行人检测,提供了hog特征的API,甚至,它提供了LBP纹理特征的API。但是,这些还远远不够。例如,如果你要进行字符识别,OpenCV并没有提供字符识别所对应的特征。这个时候,就需要你自己来编程实现了。当然,该选择什么特征来描述字符呢?哪些特征更好呢?对于这些问题,我建议你去阅读相应的会议,期刊,杂志,硕士、博士毕业论文,看看别人写的文章,自然就知道了。
        对于特征选择,OpenCV并没有提供特定的函数来进行衡量。而特征的分类能力的高低评价,有很多种分析方法,有兴趣的朋友,可以阅读"《机器学习》Tom. Mitchell(著),曾华军(译),机械工业出版社"这本书;
        对于分类器部分,OpenCV提供了SVM,CART,boost,bayes,bdt,ANN,这几种常用的算法。而这些基本已经覆盖了常用的分类器。所以,你需要做的,就是知道怎么调用其接口,各种分类器的优点和缺点(该部分,建议阅读“机器学习”这本书)。
        通过以上的分析,你或许已经发现,OpenCV不过是一个工具库而已。或者,你可以将它理解为积木,而OpenCV中的函数,则可以理解为一个一个的积木块,利用所有或者部分积木块,你可以快速的搭建起来具体的计算机视觉方面的应用(比如,字符识别,车牌识别,遗留物检测)。想必你也已经发现,在利用OpenCV这个积木来搭建具体的计算机视觉应用的时候,真正核心的,应该是这些积木块,如果你明白了积木块的工作原理,那么,是不是就可以不用这些积木块了呢?完全正确!不过,一般部分情况下,我们不需要这么做,因为,OpenCV已经帮你做好了一些工作(已经帮你做好了一些积木块,直接拿来用就是了)。但是,诸如前面提到的特征提取,很多情况下,OpenCV就无能为力了。这个时候,你就需要翻阅计算机视觉、模式识别、机器学习领域顶级会议、期刊、杂志上面发表的文章了。然后,根据这些文章中阐述的原理和方法,来编程实现你要的东西。实际上,也就等于搭建一个属于你私有的积木块。其实,OpenCV中的每一个API函数,也就是这么来的。

关键词: OpenCV C++ 编程 类库
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 沙发  发表于: 2011-12-10
OpenCV学习笔记(一)
决心开始研究OpenCV。闲言少叙,sourceforge网站最近的版本是2011年8月的OpenCV2.3.1,下载安装,我这里使用的开发环境是vs2008,网上搜了一下配置的教程,与之前的几个OpenCV版本的配置过程大体相同:(教程网上很多,知之为知之,不知百度之,我这里粗略再讲一下)


1. 配置电脑的环境变量(Path变量)(需要注销才能生效),这里需要注意网上的教程又让增加一个OPENCV变量,值为D:\Program Files\OpenCV2.3.1\build(你安装的路径中的build目录)


2. 添加包含文件和库文件,这个和前几个版本方法类似,都是去工具->选项->VC目录添加build目录下的include目录及其子目录和你电脑对应版本的lib目录(选择x86 or x64,vc9  or vc10)


下面是第一个实例:


新建一个空项目,添加源文件如下:




view plain
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <iostream>  
  
using namespace cv;  
using namespace std;  
  
int main( int argc, char** argv )  
{  
    if( argc != 2)  
    {  
     cout <<" Usage: display_image ImageToLoadAndDisplay" << endl;  
     return -1;  
    }  
      
    Mat image;  
    image = imread(argv[1], CV_LOAD_IMAGE_COLOR);   // Read the file  
  
    if(! image.data )                              // Check for invalid input  
    {  
        cout <<  "Could not open or find the image" << std::endl ;  
        return -1;  
    }  
  
    namedWindow( "Display window", CV_WINDOW_AUTOSIZE );// Create a window for display.  
    imshow( "Display window", image );                   // Show our image inside it.  
  
    waitKey(0);                                          // Wait for a keystroke in the window  
    return 0;  
}  


这段程序可以在你安装目录下的samples\cpp\tutorial_code\introduction\display_image找到,编译后,将图片test.jpg放到opencvtest.exe相同的目录中去,利用cmd命令行进入的可执行文件所在的目录,
运行opencvtest test.jpg


则会显示一个图片,第一个程序成功。如图






如果遇到找不到tbb_debug.dll文件的问题,参考这里http://www.opencv.org.cn/forum/viewtopic.php?p=52223,只是我的环境是vs2008,大同小异。祝你成功!


接下来我觉得应该好好研究一下OpenCV里的doc文件夹下的教程和使用手册,我个人觉得《学习OpenCV》这本书已经远远跟不上OpenCV发展的速度了
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 板凳  发表于: 2011-12-10
还是老话题,2.0版本对OpenCV可是进行了大刀阔斧的改革,用c++重新了大部分结构,而不是1.X版本中的c结构。这些模块包括:
core——定义了基本数据结构,包括最重要的Mat和一些其他的模块
imgproc——该模块包括了线性和非线性的图像滤波,图像的几何变换,颜色空间转换,直方图处理等等
video——该模块包括运动估计,背景分离,对象跟踪
calib3d——基本的多视角几何算法,单个立体摄像头标定,物体姿态估计,立体相似性算法,3D信息的重建
features2d——显著特征检测,描述,特征匹配
objdetect——物体检测和预定义好的分类器实例(比如人脸,眼睛,面部,人,车辆等等)
highgui——视频捕捉、图像和视频的编码解码、图形交互界面的接口
gpu——利用GPU对OpenCV模块进行加速算法
ml——机器学习模块(SVM,决策树,Boosting等等)
flann——Fast Library for Approximate Nearest Neighbors(FLANN)算法库
legacy——一些已经废弃的代码库,保留下来作为向下兼容
还有一些其他的模块,比如FLANN算法库、Google测试包、Python bingdings等等
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 地板  发表于: 2011-12-10
自从版本2.0,OpenCV采用了新的数据结构,用Mat类结构取代了之前用extended C写的cvMat和lplImage,更加好用啦,最大的好处就是更加方便的进行内存管理,对写更大的程序是很好的消息。


需要注意的几点:
1. Mat的拷贝只是复制了Mat的信息头,数据的指针也指向了被拷贝的数据地址,而没有真正新建一块内存来存放新的矩阵内容。这样带来的一个问题就是对其中一个Mat的数据操作就会对其他指向同一块数据的Mat产生灾难性的影响。


2.建立多维数组的格式是这样的
view plain
int sz[3] = {2, 2, 2};  
Mat L(3, sz, CV_8UC(1), Scalar::all(0));  


3.传统的lplImage格式也可直接转换为Mat格式
view plain
IplImage* img = cvLoadImage("greatwave.png", 1);  
Mat mtx(img); // convert IplImage* -> Mat  


如果想将新版本的Mat格式转换为老版本,则需要如下调用:


view plain
Mat I;  
IplImage* pI = &I.operator IplImage();  
CvMat* mI = &I.operator CvMat();  


不过更安全的调用格式为:
view plain
Ptr<IplImage> piI = &I.operator IplImage();  


4.Mat结构更加友好,很多操作更接近matlab的风格
5.也有Point2f,Point3f,vector等数据结构可以使用
6.RNG类可以产生随机数


7.实现颜色通道的分离使用函数split
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 4楼 发表于: 2011-12-10
2.0新版本对数据结构进行了大幅修改:


定义了DataType类


定义了Point_模板类,取代了之前版本的CvPoint、CvPoint2D32f


定义了Point3_模板类,取代了之前版本的CvPoint2D32f


定义了Size_模板类,取代了之前版本的CvSize和CvSize2D32f


定义了Rect_模板类,取代了之前版本的CvRect


RotatedRect模板类,


TermCriteria模板类,取代了之前的CvTermCriteria,这个类是作为迭代算法的终止条件的,这个类在参考手册里介绍的很简单,我查了些资料,这里介绍一下。该类变量需要3个参数,一个是类型,第二个参数为迭代的最大次数,最后一个是特定的阈值


Matx模板类。Matx模板类是对Mat类的一个拓展,从Matx类有派生出Vec类,又Vec类又派生出Scalar_类,取代了CvScalar


定义了Range类指定了一个序列的一个连续的子序列


定义了Ptr类用来对老版本的数据结构进行指针操作,更安全有效,可以防止内存的不正常使用。


最最重要的定义了Mat类来表示矩阵,取代了之前的CvMat和lplImage。Mat结构支持的操作有:


构造析构函数Mat和~Mat


对=、MatExpr、( )、CvMat、IplImage进行了运算符重载


row、col函数


rowRange、colRange


类似matlab的运算操作diag、t、inv、mul、cross、dot、zeros、one、eye


复制转换变形clone、copyTo、convertTo、assignTo、setTo、reshape、create、addref


其中copyTo函数有个妙用,不但可以复制Mat,还可以通过mask提取出感兴趣的部分


数据的操作release、resize、reserve、push_back、pop_back、locateROI、adjustROI


Mat的信息total、isContinuous、elemSize、elemSize1、type、depth、channes、step1、size、empty


定位ptr、at、begin、end


还做了几个扩展类Mat_、NAryMatlterator、SparseMat、SparseMat_取代了之前的CvSparseMat。这些类的操作运算与Mat大同小异,类声明参考core的具体头文件


当然,新版本对老版本的数据结构和函数依然支持。


新版本还在这些结构里支持dft、dct变换,我这里讲一下我的新发现PCA类、SVD类


PCA类有构造函数PCA,运算符重载(),project,backProject。SVD类有构造函数SVD,运算符重载(),compute,solveZ,backSubst


这里介绍几个我使用过的实用函数:


inRange函数可以检查Matsrc的内容是否在Matlower、Matupper之间,输出结果是一个uchar型矩阵,1表示在两者之间,否则为0,值得注意的是,Matlower,Matupper也可以用Scalar的格式


bitwise_xxx函数对两个矩阵进行位运算,结果保存在第三个矩阵当中


mixChannels函数可以实现矩阵的指定通道复制到新矩阵的指定通道


总之,新版本支持更多的数学运算,还支持一些画图操作
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 5楼 发表于: 2011-12-10
都知道,2.0版本对之前的OpenCV数据结构进行了大幅度的修改。但对之前版本的兼容是一个很重要的事情。这节就主要讨论这个问题
首先来看一下2.0版本对之前版本的进行了哪些修改
1.采用了新的数据结构Mat作为图像的容器,取代了之前的CvMat和lplImage,这个改动不是太复杂,只需适应一下新东西,而且可以自由转换
view plain
Mat I;  
IplImage pI = I;  
CvMat mI = I;  


对于指针的操作要相对复杂一些,而且还要注意内存的释放,我这里不推荐用老版本的数据结构,例如:
view plain
Mat I;  
IplImage* pI = &I.operator IplImage();  
CvMat* mI = &I.operator CvMat();  


2.对library进行了重组,将原来的一个大库根据功能结构分成具体小库,这样包含头文件的时候只需要加入你需要的库,只是原来库的子集
3.使用了cv 这个namespace来防止和其他的library 结构冲突。所以在使用的时候也要预先加上cv::关键字,这也是新版本的函数,数据都省略了cv前缀的原因,一般放在include之后,格式为:
view plain
using namespace cv; // The new C++ interface API is inside this namespace. Import it.  


QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 6楼 发表于: 2011-12-10
1. XML、YAML文件的打开和关闭
XML\YAML文件在OpenCV中的数据结构为FileStorage,打开操作例如:


view plain
string filename = "I.xml";  
FileStorage fs(filename, FileStorage::WRITE);  
\\...  
fs.open(filename, FileStorage::READ);  


文件关闭操作会在FileStorage结构销毁时自动进行,但也可调用如下函数实现
view plain
fs.release();  


2.文本和数字的输入和输出


写入文件使用  <<  运算符,例如:


view plain
fs << "iterationNr" << 100;  


读取文件,使用 >> 运算符,例如
view plain
int itNr;  
fs["iterationNr"] >> itNr;  
itNr = (int) fs["iterationNr"];  




3. OpenCV数据结构的输入和输出,和基本的C++形式相同


view plain
Mat R = Mat_<uchar >::eye (3, 3),  
T = Mat_<double>::zeros(3, 1);  
fs << "R" << R; // Write cv::Mat  
fs << "T" << T;  
fs["R"] >> R; // Read cv::Mat  
fs["T"] >> T;  




4. vector(arrays) 和 maps的输入和输出
vector要注意在第一个元素前加上“[”,在最后一个元素前加上"]"。例如:


view plain
fs << "strings" << "["; // text - string sequence  
fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";  
fs << "]"; // close sequence  


对于map结构的操作使用的符号是"{"和"}",例如:
view plain
fs << "Mapping"; // text - mapping  
fs << "{" << "One" << 1;  
fs << "Two" << 2 << "}";  


读取这些结构的时候,会用到FileNode和FileNodeIterator数据结构。对FileStorage类的[]操作符会返回FileNode数据类型,对于一连串的node,可以使用FileNodeIterator结构,例如:
view plain
FileNode n = fs["strings"]; // Read string sequence - Get node  
if (n.type() != FileNode::SEQ)  
{  
cerr << "strings is not a sequence! FAIL" << endl;  
return 1;  
}  
FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node  
for (; it != it_end; ++it)  
cout << (string)*it << endl;  




5. 读写自己的数据结构
这部分比较复杂,参考最后的实例中的MyData结构自己领悟吧


最后,我这里上一个实例,供大家参考。


源文件里填入如下代码:


view plain
#include <opencv2/core/core.hpp>  
#include <iostream>  
#include <string>  
  
using namespace cv;  
using namespace std;  
  
void help(char** av)  
{  
    cout << endl  
        << av[0] << " shows the usage of the OpenCV serialization functionality."         << endl  
        << "usage: "                                                                      << endl  
        <<  av[0] << " outputfile.yml.gz"                                                 << endl  
        << "The output file may be either XML (xml) or YAML (yml/yaml). You can even compress it by "  
        << "specifying this in its extension like xml.gz yaml.gz etc... "                  << endl  
        << "With FileStorage you can serialize objects in OpenCV by using the << and >> operators" << endl  
        << "For example: - create a class and have it serialized"                         << endl  
        << "             - use it to read and write matrices."                            << endl;  
}  
  
class MyData  
{  
public:  
    MyData() : A(0), X(0), id()  
    {}  
    explicit MyData(int) : A(97), X(CV_PI), id("mydata1234") // explicit to avoid implicit conversion  
    {}  
    void write(FileStorage& fs) const                        //Write serialization for this class  
    {  
        fs << "{" << "A" << A << "X" << X << "id" << id << "}";  
    }  
    void read(const FileNode& node)                          //Read serialization for this class  
    {  
        A = (int)node["A"];  
        X = (double)node["X"];  
        id = (string)node["id"];  
    }  
public:   // Data Members  
    int A;  
    double X;  
    string id;  
};  
  
//These write and read functions must be defined for the serialization in FileStorage to work  
void write(FileStorage& fs, const std::string&, const MyData& x)  
{  
    x.write(fs);  
}  
void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()){  
    if(node.empty())  
        x = default_value;  
    else  
        x.read(node);  
}  
  
// This function will print our custom class to the console  
ostream& operator<<(ostream& out, const MyData& m)  
{  
    out << "{ id = " << m.id << ", ";  
    out << "X = " << m.X << ", ";  
    out << "A = " << m.A << "}";  
    return out;  
}  
  
int main(int ac, char** av)  
{  
    if (ac != 2)  
    {  
        help(av);  
        return 1;  
    }  
  
    string filename = av[1];  
    { //write  
        Mat R = Mat_<uchar>::eye(3, 3),  
            T = Mat_<double>::zeros(3, 1);  
        MyData m(1);  
  
        FileStorage fs(filename, FileStorage::WRITE);  
  
        fs << "iterationNr" << 100;  
        fs << "strings" << "[";                              // text - string sequence  
        fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";  
        fs << "]";                                           // close sequence  
          
        fs << "Mapping";                              // text - mapping  
        fs << "{" << "One" << 1;  
        fs <<        "Two" << 2 << "}";                
  
        fs << "R" << R;                                      // cv::Mat  
        fs << "T" << T;  
  
        fs << "MyData" << m;                                // your own data structures  
  
        fs.release();                                       // explicit close  
        cout << "Write Done." << endl;  
    }  
  
    {//read  
        cout << endl << "Reading: " << endl;  
        FileStorage fs;  
        fs.open(filename, FileStorage::READ);  
  
        int itNr;  
        //fs["iterationNr"] >> itNr;  
        itNr = (int) fs["iterationNr"];  
        cout << itNr;  
        if (!fs.isOpened())  
        {  
            cerr << "Failed to open " << filename << endl;  
            help(av);  
            return 1;  
        }  
  
        FileNode n = fs["strings"];                         // Read string sequence - Get node  
        if (n.type() != FileNode::SEQ)  
        {  
            cerr << "strings is not a sequence! FAIL" << endl;  
            return 1;  
        }  
  
        FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node  
        for (; it != it_end; ++it)  
            cout << (string)*it << endl;  
          
          
        n = fs["Mapping"];                                // Read mappings from a sequence  
        cout << "Two  " << (int)(n["Two"]) << "; ";  
        cout << "One  " << (int)(n["One"]) << endl << endl;  
          
  
        MyData m;  
        Mat R, T;  
  
        fs["R"] >> R;                                      // Read cv::Mat  
        fs["T"] >> T;  
        fs["MyData"] >> m;                                 // Read your own structure_  
  
        cout << endl  
            << "R = " << R << endl;  
        cout << "T = " << T << endl << endl;  
        cout << "MyData = " << endl << m << endl << endl;  
  
        //Show default behavior for non existing nodes  
        cout << "Attempt to read NonExisting (should initialize the data structure with its default).";    
        fs["NonExisting"] >> m;  
        cout << endl << "NonExisting = " << endl << m << endl;  
    }  
  
    cout << endl  
        << "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl;  
  
    return 0;  
}  


编译后,在命令行进入到文件目录,执行test test.xml,运行结果如下,生成一个test . xml文件,内容如下:
view plain
  <?xml version="1.0" ?>  
- <opencv_storage>  
  <iterationNr>100</iterationNr>  
  <strings>image1.jpg Awesomeness baboon.jpg</strings>  
- <Mapping>  
  <One>1</One>  
  <Two>2</Two>  
  </Mapping>  
- <R type_id="opencv-matrix">  
  <rows>3</rows>  
  <cols>3</cols>  
  <dt>u</dt>  
  <data>1 0 0 0 1 0 0 0 1</data>  
  </R>  
- <T type_id="opencv-matrix">  
  <rows>3</rows>  
  <cols>1</cols>  
  <dt>d</dt>  
  <data>0. 0. 0.</data>  
  </T>  
- <MyData>  
  <A>97</A>  
  <X>3.1415926535897931e+000</X>  
  <id>mydata1234</id>  
  </MyData>  
  </opencv_storage>  
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 7楼 发表于: 2011-12-10
先介绍几个最基本的核滤波器相关的类


2D图像滤波器基础类BaseFilter:dst(x,y) = F(src(x,y), src(x+1,y)... src(x+wdith-1,y), src(y+1,x)... src(x+width-1, y+height-1) ); 相关的调用函数为getLinearFilter、getMorphologyFilter


单行核滤波器基础类BaseRowFilter:dst(x,y) = F(src(x,y), src(x+1,y),...src(x+width-1,y));相关的调用函数为getLinearRowFilter、getMorphologyRowFilter


单列核滤波器基础类BaseColumnFilter:dst(x,y) = F(src(x,y), src(x,y+1),...src(x,y+width-1));相关的调用函数为getColumnSumFilter、getLinearColumnFilter、getMorphologyColumnFilter


类FilterEngine:该类可以应用在对图像的任意滤波操作当中,在OpenCV滤波器函数中扮演着很重要的角色,相关的函数有createBoxFitler、createDerivFitlter、createGaussianFilter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter


基于这些类有一些基本的滤波器bilateralFilter、blur、boxFilter


还有一些形态学操作如:dilate、erode、morphologyEx


还有基于核和图像卷积的滤波器filter2D


还有一些典型的滤波器如GaussianBlur、medianBlur、Laplacian、pyrMeanShiftFiltering、sepFilter2D


还有Sobel、Scharr运算符


其他一些函数有borderInterpolate、buildPyramid、copyMakeBorder、createBoxFilter、createDirivFilter、createGaussianFliter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter、getDerivKernels、getGaussianKernel、getKernelType、getStructuringElement、pyrDown、pyrUp


还老版本的滤波器cvSmooth


这里介绍一下我使用Laplacian滤波的心得,这个函数的第三个参数为输出的图像的深度,注意经过拉普拉斯算子处理后得到的值是有正有负的,所以输出图像的深度最好为输入图像深度的2倍,才能有效防止数据溢出,如必须要使用8位的数据,可以再使用函数convertScaleAbs处理。而且要注意使用的拉普拉斯算子掩膜的中心系数为负。
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 8楼 发表于: 2011-12-10
直方图histograms也是图像处理中经常用到的一种手段。新版本对直方图不再使用之前的histogram的形式,而是用统一的Mat或者MatND的格式来存储直方图,可见新版本Mat数据结构的优势。先介绍下其相关的函数


calcHist、calcBackProject、compareHist、EMD、equalizeHist。除了这几个常用的函数以为,还有一些c函数写的直方图类CvHistogram的相关操作,如下:cvCalcBackProjectPatch、cvCalcProbDensity、cvClearHist、cvCopyHist、cvCreateHist、cvGetHistValue_XD、cvGetMinMaxHistValue、cvMakeHistHeaderForArray、cvNormalizeHist、QueryHistValue_XD、cvReleaseHist、cvSetHistBinRanges、cvThreshHist、cvCalcPGH


calcHist函数为计算图像的直方图,使用方法如下:


view plain
// C++:  
void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )  
// C++:  
void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )  


arrays为输入图像指针,narrays为输入图像的个数,channels为用来计算直方图的通道列表,mask为掩膜矩阵,不为空的时候,只计算arrays中的掩膜区域的直方图,hist为输出的直方图矩阵,dims为直方图矩阵的维度,histSize为每一维直方图矩阵的大小,ranges为每一维直方图元素的取值范围,是一个2维数组的地址,uniform为直方图是否为统一模式,统一模式下会拉伸为range的大小,accumulate为累计标志,方便直方图的更新,不需要重新计算


举几个实例方便大家理解:


对于图像为灰度图,调用方式如下:


view plain
int histSize = 255;  
float ranges[] = {0, 255};  
const float* histRange = {ranges};  
calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, &histRange);  


直方图的归一化已经不再适合cvNormalizeHist这个函数了,只需要用对矩阵的归一化函数normalize就可以实现了。
直方图均衡化函数为equalizeHist,这个函数比较简单,这里就不详细介绍了


直方图的比较函数为compareHist,函数返回值为两矩阵的相似程度,相似度衡量的办法目前支持4种


– CV_COMP_CORREL Correlation相关系数,相同为1,相似度范围为[ 1, 0 )


– CV_COMP_CHISQR Chi-Square卡方,相同为0,相似度范围为[ 0, +inf )


– CV_COMP_INTERSECT Intersection直方图交,数越大越相似,,相似度范围为[ 0, +inf )


– CV_COMP_BHATTACHARYYA Bhattacharyya distance做常态分别比对的Bhattacharyya 距离,相同为0,,相似度范围为[ 0, +inf )


计算反向投影图函数为calcBackProject。所谓反向投影图就是一个概率密度图。calcBackProject的输入为图像及其直方图,输出与待跟踪图像大小相同,每一个像素点表示该点为目标区域的概率。这个点越亮,该点属于物体的概率越大。关于反向直方图,可以参考一下这篇文章http://blog.163.com/thomaskjh@126/blog/static/370829982010112810358501/,这个函数使我们利用特征直方图寻找图片中的特征区域变得更加方便容易。这里举一个比较常用的例子:如果已经有一个肤色的特征直方图,则可以在待检测图像中利用直方图方向投影图找出图片中的肤色区域。
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8532
金币
2762
威望
3231
贡献值
0
元宝
0
只看该作者 9楼 发表于: 2011-12-10
直方图histograms也是图像处理中经常用到的一种手段。新版本对直方图不再使用之前的histogram的形式,而是用统一的Mat或者MatND的格式来存储直方图,可见新版本Mat数据结构的优势。先介绍下其相关的函数


calcHist、calcBackProject、compareHist、EMD、equalizeHist。除了这几个常用的函数以为,还有一些c函数写的直方图类CvHistogram的相关操作,如下:cvCalcBackProjectPatch、cvCalcProbDensity、cvClearHist、cvCopyHist、cvCreateHist、cvGetHistValue_XD、cvGetMinMaxHistValue、cvMakeHistHeaderForArray、cvNormalizeHist、QueryHistValue_XD、cvReleaseHist、cvSetHistBinRanges、cvThreshHist、cvCalcPGH


calcHist函数为计算图像的直方图,使用方法如下:


view plain
// C++:  
void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )  
// C++:  
void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const ?oat** ranges, bool uniform=true, bool accumulate=false )  


arrays为输入图像指针,narrays为输入图像的个数,channels为用来计算直方图的通道列表,mask为掩膜矩阵,不为空的时候,只计算arrays中的掩膜区域的直方图,hist为输出的直方图矩阵,dims为直方图矩阵的维度,histSize为每一维直方图矩阵的大小,ranges为每一维直方图元素的取值范围,是一个2维数组的地址,uniform为直方图是否为统一模式,统一模式下会拉伸为range的大小,accumulate为累计标志,方便直方图的更新,不需要重新计算


举几个实例方便大家理解:


对于图像为灰度图,调用方式如下:


view plain
int histSize = 255;  
float ranges[] = {0, 255};  
const float* histRange = {ranges};  
calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, &histRange);  


直方图的归一化已经不再适合cvNormalizeHist这个函数了,只需要用对矩阵的归一化函数normalize就可以实现了。
直方图均衡化函数为equalizeHist,这个函数比较简单,这里就不详细介绍了


直方图的比较函数为compareHist,函数返回值为两矩阵的相似程度,相似度衡量的办法目前支持4种


– CV_COMP_CORREL Correlation相关系数,相同为1,相似度范围为[ 1, 0 )


– CV_COMP_CHISQR Chi-Square卡方,相同为0,相似度范围为[ 0, +inf )


– CV_COMP_INTERSECT Intersection直方图交,数越大越相似,,相似度范围为[ 0, +inf )


– CV_COMP_BHATTACHARYYA Bhattacharyya distance做常态分别比对的Bhattacharyya 距离,相同为0,,相似度范围为[ 0, +inf )


计算反向投影图函数为calcBackProject。所谓反向投影图就是一个概率密度图。calcBackProject的输入为图像及其直方图,输出与待跟踪图像大小相同,每一个像素点表示该点为目标区域的概率。这个点越亮,该点属于物体的概率越大。关于反向直方图,可以参考一下这篇文章http://blog.163.com/thomaskjh@126/blog/static/370829982010112810358501/,这个函数使我们利用特征直方图寻找图片中的特征区域变得更加方便容易。这里举一个比较常用的例子:如果已经有一个肤色的特征直方图,则可以在待检测图像中利用直方图方向投影图找出图片中的肤色区域。
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
描述
快速回复

您目前还是游客,请 登录注册
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容