OpenCV学习笔记(六)(七)(八)(九)(十)

OpenCV学习笔记(六)——对XML和YAML文件实现I/O操作


1. XML、YAML文件的打开和关闭

XML\YAML文件在OpenCV中的数据结构为FileStorage,打开操作例如:

[cpp]  view plain  copy
  1. string filename = "I.xml";  
  2. FileStorage fs(filename, FileStorage::WRITE);  
  3. \\...  
  4. fs.open(filename, FileStorage::READ);  

文件关闭操作会在FileStorage结构销毁时自动进行,但也可调用如下函数实现

[cpp]  view plain  copy
  1. fs.release();  

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

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

[cpp]  view plain  copy
  1. fs << "iterationNr" << 100;  

读取文件,使用 >> 运算符,例如

[cpp]  view plain  copy
  1. int itNr;  
  2. fs["iterationNr"] >> itNr;  
  3. itNr = (int) fs["iterationNr"];  


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

[cpp]  view plain  copy
  1. Mat R = Mat_::eye (3, 3),  
  2. T = Mat_<double>::zeros(3, 1);  
  3. fs << "R" << R; // Write cv::Mat  
  4. fs << "T" << T;  
  5. fs["R"] >> R; // Read cv::Mat  
  6. fs["T"] >> T;  


4. vector(arrays) 和 maps的输入和输出

vector要注意在第一个元素前加上“[”,在最后一个元素前加上"]"。例如:

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

对于map结构的操作使用的符号是"{"和"}",例如:

[cpp]  view plain  copy
  1. fs << "Mapping"// text - mapping  
  2. fs << "{" << "One" << 1;  
  3. fs << "Two" << 2 << "}";  

读取这些结构的时候,会用到FileNode和FileNodeIterator数据结构。对FileStorage类的[]操作符会返回FileNode数据类型,对于一连串的node,可以使用FileNodeIterator结构,例如:

[cpp]  view plain  copy
  1. FileNode n = fs["strings"]; // Read string sequence - Get node  
  2. if (n.type() != FileNode::SEQ)  
  3. {  
  4. cerr << "strings is not a sequence! FAIL" << endl;  
  5. return 1;  
  6. }  
  7. FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node  
  8. for (; it != it_end; ++it)  
  9. cout << (string)*it << endl;  


5. 读写自己的数据结构

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

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

源文件里填入如下代码:

[cpp]  view plain  copy
  1. #include   
  2. #include   
  3. #include   
  4.   
  5. using namespace cv;  
  6. using namespace std;  
  7.   
  8. void help(char** av)  
  9. {  
  10.     cout << endl   
  11.         << av[0] << " shows the usage of the OpenCV serialization functionality."         << endl  
  12.         << "usage: "                                                                      << endl  
  13.         <<  av[0] << " outputfile.yml.gz"                                                 << endl  
  14.         << "The output file may be either XML (xml) or YAML (yml/yaml). You can even compress it by "  
  15.         << "specifying this in its extension like xml.gz yaml.gz etc... "                  << endl  
  16.         << "With FileStorage you can serialize objects in OpenCV by using the << and >> operators" << endl  
  17.         << "For example: - create a class and have it serialized"                         << endl  
  18.         << "             - use it to read and write matrices."                            << endl;  
  19. }  
  20.   
  21. class MyData  
  22. {  
  23. public:  
  24.     MyData() : A(0), X(0), id()  
  25.     {}  
  26.     explicit MyData(int) : A(97), X(CV_PI), id("mydata1234"// explicit to avoid implicit conversion  
  27.     {}  
  28.     void write(FileStorage& fs) const                        //Write serialization for this class  
  29.     {  
  30.         fs << "{" << "A" << A << "X" << X << "id" << id << "}";  
  31.     }  
  32.     void read(const FileNode& node)                          //Read serialization for this class  
  33.     {  
  34.         A = (int)node["A"];  
  35.         X = (double)node["X"];  
  36.         id = (string)node["id"];  
  37.     }  
  38. public:   // Data Members  
  39.     int A;  
  40.     double X;  
  41.     string id;  
  42. };  
  43.   
  44. //These write and read functions must be defined for the serialization in FileStorage to work  
  45. void write(FileStorage& fs, const std::string&, const MyData& x)  
  46. {  
  47.     x.write(fs);  
  48. }  
  49. void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()){  
  50.     if(node.empty())  
  51.         x = default_value;  
  52.     else  
  53.         x.read(node);  
  54. }  
  55.   
  56. // This function will print our custom class to the console  
  57. ostream& operator<<(ostream& out, const MyData& m)   
  58. {   
  59.     out << "{ id = " << m.id << ", ";  
  60.     out << "X = " << m.X << ", ";  
  61.     out << "A = " << m.A << "}";  
  62.     return out;  
  63. }  
  64.   
  65. int main(int ac, char** av)  
  66. {  
  67.     if (ac != 2)  
  68.     {  
  69.         help(av);  
  70.         return 1;  
  71.     }  
  72.   
  73.     string filename = av[1];  
  74.     { //write  
  75.         Mat R = Mat_::eye(3, 3),  
  76.             T = Mat_<double>::zeros(3, 1);  
  77.         MyData m(1);  
  78.   
  79.         FileStorage fs(filename, FileStorage::WRITE);  
  80.   
  81.         fs << "iterationNr" << 100;  
  82.         fs << "strings" << "[";                              // text - string sequence  
  83.         fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";  
  84.         fs << "]";                                           // close sequence  
  85.           
  86.         fs << "Mapping";                              // text - mapping  
  87.         fs << "{" << "One" << 1;  
  88.         fs <<        "Two" << 2 << "}";                 
  89.   
  90.         fs << "R" << R;                                      // cv::Mat  
  91.         fs << "T" << T;  
  92.   
  93.         fs << "MyData" << m;                                // your own data structures  
  94.   
  95.         fs.release();                                       // explicit close  
  96.         cout << "Write Done." << endl;  
  97.     }  
  98.   
  99.     {//read  
  100.         cout << endl << "Reading: " << endl;  
  101.         FileStorage fs;   
  102.         fs.open(filename, FileStorage::READ);  
  103.   
  104.         int itNr;   
  105.         //fs["iterationNr"] >> itNr;  
  106.         itNr = (int) fs["iterationNr"];  
  107.         cout << itNr;  
  108.         if (!fs.isOpened())  
  109.         {  
  110.             cerr << "Failed to open " << filename << endl;  
  111.             help(av);  
  112.             return 1;  
  113.         }  
  114.   
  115.         FileNode n = fs["strings"];                         // Read string sequence - Get node  
  116.         if (n.type() != FileNode::SEQ)  
  117.         {  
  118.             cerr << "strings is not a sequence! FAIL" << endl;  
  119.             return 1;  
  120.         }  
  121.   
  122.         FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node  
  123.         for (; it != it_end; ++it)  
  124.             cout << (string)*it << endl;  
  125.           
  126.           
  127.         n = fs["Mapping"];                                // Read mappings from a sequence  
  128.         cout << "Two  " << (int)(n["Two"]) << "; ";   
  129.         cout << "One  " << (int)(n["One"]) << endl << endl;   
  130.           
  131.   
  132.         MyData m;  
  133.         Mat R, T;  
  134.   
  135.         fs["R"] >> R;                                      // Read cv::Mat  
  136.         fs["T"] >> T;  
  137.         fs["MyData"] >> m;                                 // Read your own structure_  
  138.   
  139.         cout << endl   
  140.             << "R = " << R << endl;  
  141.         cout << "T = " << T << endl << endl;  
  142.         cout << "MyData = " << endl << m << endl << endl;  
  143.   
  144.         //Show default behavior for non existing nodes  
  145.         cout << "Attempt to read NonExisting (should initialize the data structure with its default).";    
  146.         fs["NonExisting"] >> m;  
  147.         cout << endl << "NonExisting = " << endl << m << endl;  
  148.     }  
  149.   
  150.     cout << endl   
  151.         << "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl;  
  152.   
  153.     return 0;  
  154. }  

编译后,在命令行进入到文件目录,执行test test.xml,运行结果如下, 生成一个test . xml文件,内容如下:

[html]  view plain  copy
  1.   xml version="1.0" ?>   
  2. <opencv_storage>  
  3.   <iterationNr>100iterationNr>   
  4.   <strings>image1.jpg Awesomeness baboon.jpgstrings>   
  5. <Mapping>  
  6.   <One>1One>   
  7.   <Two>2Two>   
  8.   Mapping>  
  9. <R type_id="opencv-matrix">  
  10.   <rows>3rows>   
  11.   <cols>3cols>   
  12.   <dt>udt>   
  13.   <data>1 0 0 0 1 0 0 0 1data>   
  14.   R>  
  15. <T type_id="opencv-matrix">  
  16.   <rows>3rows>   
  17.   <cols>1cols>   
  18.   <dt>ddt>   
  19.   <data>0. 0. 0.data>   
  20.   T>  
  21. <MyData>  
  22.   <A>97A>   
  23.   <X>3.1415926535897931e+000X>   
  24.   <id>mydata1234id>   
  25.   MyData>  
  26.   opencv_storage>  


OpenCV学习笔记(七)——图像处理之滤波器ImgProc


先介绍几个最基本的核滤波器相关的类

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处理。而且要注意使用的拉普拉斯算子掩膜的中心系数为负。



OpenCV学习笔记(八)——图像处理之直方图ImgProc

直方图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函数为计算图像的直方图,使用方法如下:

[cpp]  view plain  copy
  1. // C++:   
  2. void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=truebool accumulate=false )  
  3. // C++:   
  4. void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const float** ranges, bool uniform=truebool accumulate=false )  

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

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

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

[cpp]  view plain  copy
  1. int histSize = 255;  
  2. float ranges[] = {0, 255};  
  3. const float* histRange = {ranges};  
  4. 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/ ,这个函数使我们利用特征直方图寻找图片中的特征区域变得更加方便容易。这里举一个比较常用的例子:如果已经有一个肤色的特征直方图,则可以在待检测图像中利用直方图方向投影图找出图片中的肤色区域。


OpenCV学习笔记(九)——2维特征Feature2D

基于特征点的图像匹配是图像处理中经常会遇到的问题,手动选取特征点太麻烦了。比较经典常用的特征点自动提取的办法有Harris特征、SIFT特征、SURF特征。

先介绍利用SURF特征的特征描述办法,其操作封装在类SurfFeatureDetector中,利用类内的detect函数可以检测出SURF特征的关键点,保存在vector容器中。第二部利用SurfDescriptorExtractor类进行特征向量的相关计算。将之前的vector变量变成向量矩阵形式保存在Mat中。最后强行匹配两幅图像的特征向量,利用了类BruteForceMatcher中的函数match。代码如下:

[cpp]  view plain  copy
  1. /** 
  2.  * @file SURF_descriptor 
  3.  * @brief SURF detector + descritpor + BruteForce Matcher + drawing matches with OpenCV functions 
  4.  * @author A. Huaman 
  5.  */  
  6.   
  7. #include   
  8. #include   
  9. #include "opencv2/core/core.hpp"  
  10. #include "opencv2/features2d/features2d.hpp"  
  11. #include "opencv2/highgui/highgui.hpp"  
  12.   
  13. using namespace cv;  
  14.   
  15. void readme();  
  16.   
  17. /** 
  18.  * @function main 
  19.  * @brief Main function 
  20.  */  
  21. int main( int argc, char** argv )  
  22. {  
  23.   if( argc != 3 )  
  24.   { return -1; }  
  25.   
  26.   Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );  
  27.   Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );  
  28.     
  29.   if( !img_1.data || !img_2.data )  
  30.   { return -1; }  
  31.   
  32.   //-- Step 1: Detect the keypoints using SURF Detector  
  33.   int minHessian = 400;  
  34.   
  35.   SurfFeatureDetector detector( minHessian );  
  36.   
  37.   std::vector keypoints_1, keypoints_2;  
  38.   
  39.   detector.detect( img_1, keypoints_1 );  
  40.   detector.detect( img_2, keypoints_2 );  
  41.   
  42.   //-- Step 2: Calculate descriptors (feature vectors)  
  43.   SurfDescriptorExtractor extractor;  
  44.   
  45.   Mat descriptors_1, descriptors_2;  
  46.   
  47.   extractor.compute( img_1, keypoints_1, descriptors_1 );  
  48.   extractor.compute( img_2, keypoints_2, descriptors_2 );  
  49.   
  50.   //-- Step 3: Matching descriptor vectors with a brute force matcher  
  51.   BruteForceMatcher< L2<float> > matcher;  
  52.   std::vector< DMatch > matches;  
  53.   matcher.match( descriptors_1, descriptors_2, matches );  
  54.   
  55.   //-- Draw matches  
  56.   Mat img_matches;  
  57.   drawMatches( img_1, keypoints_1, img_2, keypoints_2, matches, img_matches );   
  58.   
  59.   //-- Show detected matches  
  60.   imshow("Matches", img_matches );  
  61.   
  62.   waitKey(0);  
  63.   
  64.   return 0;  
  65. }  
  66.   
  67. /** 
  68.  * @function readme 
  69.  */  
  70. void readme()  
  71. { std::cout << " Usage: ./SURF_descriptor  " << std::endl; }  

当然,进行强匹配的效果不够理想,这里再介绍一种FLANN特征匹配算法。前两步与上述代码相同,第三步利用FlannBasedMatcher类进行特征匹配,并只保留好的特征匹配点,代码如下:

[cpp]  view plain  copy
  1. //-- Step 3: Matching descriptor vectors using FLANN matcher  
  2. FlannBasedMatcher matcher;  
  3. std::vector< DMatch > matches;  
  4. matcher.match( descriptors_1, descriptors_2, matches );  
  5.   
  6. double max_dist = 0; double min_dist = 100;  
  7.   
  8. //-- Quick calculation of max and min distances between keypoints  
  9. forint i = 0; i < descriptors_1.rows; i++ )  
  10. double dist = matches[i].distance;  
  11.   if( dist < min_dist ) min_dist = dist;  
  12.   if( dist > max_dist ) max_dist = dist;  
  13. }  
  14.   
  15. printf("-- Max dist : %f \n", max_dist );  
  16. printf("-- Min dist : %f \n", min_dist );  
  17.   
  18. //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist )  
  19. //-- PS.- radiusMatch can also be used here.  
  20. std::vector< DMatch > good_matches;  
  21.   
  22. forint i = 0; i < descriptors_1.rows; i++ )  
  23. if( matches[i].distance < 2*min_dist )  
  24.   { good_matches.push_back( matches[i]); }  
  25. }    
  26.   
  27. //-- Draw only "good" matches  
  28. Mat img_matches;  
  29. drawMatches( img_1, keypoints_1, img_2, keypoints_2,   
  30.              good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),   
  31.              vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );   
  32.   
  33. //-- Show detected matches  
  34. imshow( "Good Matches", img_matches );  

在FLANN特征匹配的基础上,还可以进一步利用Homography映射找出已知物体。具体来说就是利用findHomography函数利用匹配的关键点找出相应的变换,再利用perspectiveTransform函数映射点群。具体代码如下:

[cpp]  view plain  copy
  1. //-- Localize the object from img_1 in img_2   
  2. std::vector obj;  
  3. std::vector scene;  
  4.   
  5. forint i = 0; i < good_matches.size(); i++ )  
  6. {  
  7.   //-- Get the keypoints from the good matches  
  8.   obj.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );  
  9.   scene.push_back( keypoints_2[ good_matches[i].trainIdx ].pt );   
  10. }  
  11.   
  12. Mat H = findHomography( obj, scene, CV_RANSAC );  
  13.   
  14. //-- Get the corners from the image_1 ( the object to be "detected" )  
  15. Point2f obj_corners[4] = { cvPoint(0,0), cvPoint( img_1.cols, 0 ), cvPoint( img_1.cols, img_1.rows ), cvPoint( 0, img_1.rows ) };  
  16. Point scene_corners[4];  
  17.   
  18. //-- Map these corners in the scene ( image_2)  
  19. forint i = 0; i < 4; i++ )  
  20. {  
  21.   double x = obj_corners[i].x;   
  22.   double y = obj_corners[i].y;  
  23.   
  24.   double Z = 1./( H.at<double>(2,0)*x + H.at<double>(2,1)*y + H.at<double>(2,2) );  
  25.   double X = ( H.at<double>(0,0)*x + H.at<double>(0,1)*y + H.at<double>(0,2) )*Z;  
  26.   double Y = ( H.at<double>(1,0)*x + H.at<double>(1,1)*y + H.at<double>(1,2) )*Z;  
  27.   scene_corners[i] = cvPoint( cvRound(X) + img_1.cols, cvRound(Y) );  
  28. }    
  29.    
  30. //-- Draw lines between the corners (the mapped object in the scene - image_2 )  
  31. line( img_matches, scene_corners[0], scene_corners[1], Scalar(0, 255, 0), 2 );  
  32. line( img_matches, scene_corners[1], scene_corners[2], Scalar( 0, 255, 0), 2 );  
  33. line( img_matches, scene_corners[2], scene_corners[3], Scalar( 0, 255, 0), 2 );  
  34. line( img_matches, scene_corners[3], scene_corners[0], Scalar( 0, 255, 0), 2 );  
  35.   
  36. //-- Show detected matches  
  37. imshow( "Good Matches & Object detection", img_matches );  

然后再看一下Harris特征检测,在计算机视觉中,通常需要找出两帧图像的匹配点,如果能找到两幅图像如何相关,就能提取出两幅图像的信息。我们说的特征的最大特点就是它具有唯一可识别这一特点,图像特征的类型通常指边界、角点(兴趣点)、斑点(兴趣区域)。角点就是图像的一个局部特征,应用广泛。harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高,但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。具体实现就是使用函数cornerHarris实现。

除了利用Harris进行角点检测,还可以利用Shi-Tomasi方法进行角点检测。使用函数goodFeaturesToTrack对角点进行检测,效果也不错。也可以自己制作角点检测的函数,需要用到cornerMinEigenVal函数和minMaxLoc函数,最后的特征点选取,判断条件要根据自己的情况编辑。如果对特征点,角点的精度要求更高,可以用cornerSubPix函数将角点定位到子像素。



OpenCV学习笔记(十)——图形交互和媒体接口HighGUI


OpenCV提供一个功能强大的UI接口,可以在MFC、Qt、WinForms、Cocoa等平台下使用,甚至不需要其他的平台。新版本的HighGUI接口包括:

创建并控制窗口,该窗口可以显示图片并记录其内容

为窗口添加了trackbars控件,可以方便利用鼠标进行控制而不是之前版本的只能利用键盘

读写硬盘和内存的图片

读取摄像头的视频、读写视频文件

先来介绍UI,包括函数createTrackbar、getTrackbarPos、setTrackbarPos、imshow、namedWindow、destroyWindow、destroyAllWindows、MoveWindow、ResizeWindow、SetMouseCallback、waitKey。这些函数保证了图像的基本处理、tarckbar的控制和鼠标键盘的响应

介绍一下读写图像视频的函数:图像相关的函数有imdecode、imencode、imread、imwrite。读取视频相关为VideoCapture类,负责捕捉文件和摄像头的视频,该类内有成员函数VideoCapture、open、isOpened、release、grab、retrieve、read、get、set,写视频的类为VideoWriter,类内有成员函数VideoWriter、open、isOpened、write

新版本还为Qt做了新函数,这里就不介绍了,有兴趣的朋友可以自己看一下参考手册的第四章第三节。

这里介绍几个常用的新功能,首先介绍一下添加滑杆控件Trackbar。调用函数为:

[cpp]  view plain  copy
  1. createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar );  

第一个参数为字符串作为标签,第二个参数为所在窗口的名字,第三个参数为存储滑杆位置的值地址,其范围为0~alpha_slider_max(第四个参数),最后一个参数为移动滑杆时调用的回调函数名。
OpenCV2.0版本加强了对视频处理的支持,不再需要对一组连续的图片进行处理,可以进行实时的图像采集和记录以及存储。视频的操作基本都被封装在VideoCapture类中。打开视频可以可以通过如下代码实现:
[cpp]  view plain  copy
  1. VideoCapture captRefrnc(sourceReference);  
  2. // or  
  3. VideoCapture captUndTst;  
  4. captUndTst.open(sourceCompareWith);  

其中sourceReference和sourceCompareWith为string型,为文件名。还可以通过isOpened函数检测视频是否成功打开。也可以调用release函数提前关闭视频。还可以讲VideoCapture放到Mat结构中,因为视频流是一连串的,可以通过read函数或>>操作符逐帧的读取,例如:
[cpp]  view plain  copy
  1. Mat frameReference, frameUnderTest;  
  2. captRefrnc >> frameReference;  
  3. captUndTst.open(frameUnderTest);  

read函数只能逐帧的抓取,如果要抓取某一帧,可以成对的调用grab函数和retrieve函数。get函数可以获取视频相关信息。set函数可以控制视频的一些值,比如是指视频的当前位置或帧数。

可以使用VideoWriter类创建新视频,其open,isOpened函数调用方法类似,write函数或<<运算符向视频写入内容,可以使用split函数和merge函数单独调整RGB通道的值

今日,被一个网友指出,说OpenCV以前提供的读写功能采用VFW,效率低下且有些格式支持不好。而 OpenCV 2.0 内置了videoInput Library,可以自动在VFW和DirectShow间切换。videoInput是老外写的功能强大的开源视频处理库。是一个第三方库,2.0~2.2的版本专门有一个3rdparty对该库进行支持,而在最新的2.3版本中,已经讲videoInput库集成到highgui中了,想使用它的话,只需要在cmake中设置宏WITH_VIDEOiNPUT=OFF/ON即可。

以后有新学到的东西都会陆续补充进来。



from: http://blog.csdn.net/yang_xian521/article/category/910716

你可能感兴趣的:(OpenCV,OpenCV,学习笔记,计算机视觉)