OpenCV學習筆記(六)——對XML和YAML文件實現I/O操作
1. XML、YAML文件的打開和關閉
XML\YAML文件在OpenCV中的數據結構為FileStorage,打開操作例如:
[cpp]?view plain
?copy string?filename?=?"I.xml";?? FileStorage?fs(filename,?FileStorage::WRITE);?? \\...?? fs.open(filename,?FileStorage::READ);??
文件關閉操作會在FileStorage結構銷毀時自動進行,但也可調用如下函數實現
[cpp]?view plain
?copy fs.release();??
2.文本和數字的輸入和輸出
寫入文件使用 ?<< ?運算符,例如:
[cpp]?view plain
?copy fs?<<?"iterationNr"?<<?100;??
讀取文件,使用 >> 運算符,例如
[cpp]?view plain
?copy int?itNr;?? fs["iterationNr"]?>>?itNr;?? itNr?=?(int)?fs["iterationNr"];??
3. OpenCV數據結構的輸入和輸出,和基本的C++形式相同
[cpp]?view plain
?copy Mat?R?=?Mat_<uchar?>::eye?(3,?3),?? T?=?Mat_<double>::zeros(3,?1);?? fs?<<?"R"?<<?R;??? fs?<<?"T"?<<?T;?? fs["R"]?>>?R;??? fs["T"]?>>?T;??
4. vector(arrays) 和 maps的輸入和輸出
vector要注意在第一個元素前加上“[”,在最后一個元素前加上"]"。例如:
[cpp]?view plain
?copy fs?<<?"strings"?<<?"[";??? fs?<<?"image1.jpg"?<<?"Awesomeness"?<<?"baboon.jpg";?? fs?<<?"]";???
對于map結構的操作使用的符號是"{"和"}",例如:
[cpp]?view plain
?copy fs?<<?"Mapping";??? fs?<<?"{"?<<?"One"?<<?1;?? fs?<<?"Two"?<<?2?<<?"}";??
讀取這些結構的時候,會用到FileNode和FileNodeIterator數據結構。對FileStorage類的[]操作符會返回FileNode數據類型,對于一連串的node,可以使用FileNodeIterator結構,例如:
[cpp]?view plain
?copy FileNode?n?=?fs["strings"];??? if?(n.type()?!=?FileNode::SEQ)?? {?? cerr?<<?"strings?is?not?a?sequence!?FAIL"?<<?endl;?? return?1;?? }?? FileNodeIterator?it?=?n.begin(),?it_end?=?n.end();??? for?(;?it?!=?it_end;?++it)?? cout?<<?(string)*it?<<?endl;??
5. 讀寫自己的數據結構
這部分比較復雜,參考最后的實例中的MyData結構自己領悟吧
最后,我這里上一個實例,供大家參考。
源文件里填入如下代碼:
[cpp]?view plain
?copy #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")??? ????{}?? ????void?write(FileStorage&?fs)?const?????????????????????????? ????{?? ????????fs?<<?"{"?<<?"A"?<<?A?<<?"X"?<<?X?<<?"id"?<<?id?<<?"}";?? ????}?? ????void?read(const?FileNode&?node)???????????????????????????? ????{?? ????????A?=?(int)node["A"];?? ????????X?=?(double)node["X"];?? ????????id?=?(string)node["id"];?? ????}?? public:????? ????int?A;?? ????double?X;?? ????string?id;?? };?? ?? ?? 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);?? }?? ?? ?? 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];?? ????{??? ????????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"?<<?"[";???????????????????????????????? ????????fs?<<?"image1.jpg"?<<?"Awesomeness"?<<?"baboon.jpg";?? ????????fs?<<?"]";????????????????????????????????????????????? ?????????? ????????fs?<<?"Mapping";???????????????????????????????? ????????fs?<<?"{"?<<?"One"?<<?1;?? ????????fs?<<????????"Two"?<<?2?<<?"}";????????????????? ?? ????????fs?<<?"R"?<<?R;???????????????????????????????????????? ????????fs?<<?"T"?<<?T;?? ?? ????????fs?<<?"MyData"?<<?m;?????????????????????????????????? ?? ????????fs.release();????????????????????????????????????????? ????????cout?<<?"Write?Done."?<<?endl;?? ????}?? ?? ????{?? ????????cout?<<?endl?<<?"Reading:?"?<<?endl;?? ????????FileStorage?fs;??? ????????fs.open(filename,?FileStorage::READ);?? ?? ????????int?itNr;??? ?????????? ????????itNr?=?(int)?fs["iterationNr"];?? ????????cout?<<?itNr;?? ????????if?(!fs.isOpened())?? ????????{?? ????????????cerr?<<?"Failed?to?open?"?<<?filename?<<?endl;?? ????????????help(av);?? ????????????return?1;?? ????????}?? ?? ????????FileNode?n?=?fs["strings"];??????????????????????????? ????????if?(n.type()?!=?FileNode::SEQ)?? ????????{?? ????????????cerr?<<?"strings?is?not?a?sequence!?FAIL"?<<?endl;?? ????????????return?1;?? ????????}?? ?? ????????FileNodeIterator?it?=?n.begin(),?it_end?=?n.end();??? ????????for?(;?it?!=?it_end;?++it)?? ????????????cout?<<?(string)*it?<<?endl;?? ?????????? ?????????? ????????n?=?fs["Mapping"];?????????????????????????????????? ????????cout?<<?"Two??"?<<?(int)(n["Two"])?<<?";?";??? ????????cout?<<?"One??"?<<?(int)(n["One"])?<<?endl?<<?endl;??? ?????????? ?? ????????MyData?m;?? ????????Mat?R,?T;?? ?? ????????fs["R"]?>>?R;???????????????????????????????????????? ????????fs["T"]?>>?T;?? ????????fs["MyData"]?>>?m;??????????????????????????????????? ?? ????????cout?<<?endl??? ????????????<<?"R?=?"?<<?R?<<?endl;?? ????????cout?<<?"T?=?"?<<?T?<<?endl?<<?endl;?? ????????cout?<<?"MyData?=?"?<<?endl?<<?m?<<?endl?<<?endl;?? ?? ?????????? ????????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文件,內容如下:
[html]?view plain
?copy ??<?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>??
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 ?? 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?)?? ?? 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為累計標志,方便直方圖的更新,不需要重新計算
舉幾個實例方便大家理解:
對于圖像為灰度圖,調用方式如下:
[cpp]?view plain
?copy 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/
,這個函數使我們利用特征直方圖尋找圖片中的特征區域變得更加方便容易。這里舉一個比較常用的例子:如果已經有一個膚色的特征直方圖,則可以在待檢測圖像中利用直方圖方向投影圖找出圖片中的膚色區域。
OpenCV學習筆記(九)——2維特征Feature2D
基于特征點的圖像匹配是圖像處理中經常會遇到的問題,手動選取特征點太麻煩了。比較經典常用的特征點自動提取的辦法有Harris特征、SIFT特征、SURF特征。
先介紹利用SURF特征的特征描述辦法,其操作封裝在類SurfFeatureDetector中,利用類內的detect函數可以檢測出SURF特征的關鍵點,保存在vector容器中。第二部利用SurfDescriptorExtractor類進行特征向量的相關計算。將之前的vector變量變成向量矩陣形式保存在Mat中。最后強行匹配兩幅圖像的特征向量,利用了類BruteForceMatcher中的函數match。代碼如下:
[cpp]?view plain
?copy ? ? ? ? ?? ?? #include?<stdio.h>?? #include?<iostream>?? #include?"opencv2/core/core.hpp"?? #include?"opencv2/features2d/features2d.hpp"?? #include?"opencv2/highgui/highgui.hpp"?? ?? using?namespace?cv;?? ?? void?readme();?? ?? ? ? ? ?? int?main(?int?argc,?char**?argv?)?? {?? ??if(?argc?!=?3?)?? ??{?return?-1;?}?? ?? ??Mat?img_1?=?imread(?argv[1],?CV_LOAD_IMAGE_GRAYSCALE?);?? ??Mat?img_2?=?imread(?argv[2],?CV_LOAD_IMAGE_GRAYSCALE?);?? ???? ??if(?!img_1.data?||?!img_2.data?)?? ??{?return?-1;?}?? ?? ???? ??int?minHessian?=?400;?? ?? ??SurfFeatureDetector?detector(?minHessian?);?? ?? ??std::vector<KeyPoint>?keypoints_1,?keypoints_2;?? ?? ??detector.detect(?img_1,?keypoints_1?);?? ??detector.detect(?img_2,?keypoints_2?);?? ?? ???? ??SurfDescriptorExtractor?extractor;?? ?? ??Mat?descriptors_1,?descriptors_2;?? ?? ??extractor.compute(?img_1,?keypoints_1,?descriptors_1?);?? ??extractor.compute(?img_2,?keypoints_2,?descriptors_2?);?? ?? ???? ??BruteForceMatcher<?L2<float>?>?matcher;?? ??std::vector<?DMatch?>?matches;?? ??matcher.match(?descriptors_1,?descriptors_2,?matches?);?? ?? ???? ??Mat?img_matches;?? ??drawMatches(?img_1,?keypoints_1,?img_2,?keypoints_2,?matches,?img_matches?);??? ?? ???? ??imshow("Matches",?img_matches?);?? ?? ??waitKey(0);?? ?? ??return?0;?? }?? ?? ? ? ?? void?readme()?? {?std::cout?<<?"?Usage:?./SURF_descriptor?<img1>?<img2>"?<<?std::endl;?}??
當然,進行強匹配的效果不夠理想,這里再介紹一種FLANN特征匹配算法。前兩步與上述代碼相同,第三步利用FlannBasedMatcher類進行特征匹配,并只保留好的特征匹配點,代碼如下:
[cpp]?view plain
?copy ?? FlannBasedMatcher?matcher;?? std::vector<?DMatch?>?matches;?? matcher.match(?descriptors_1,?descriptors_2,?matches?);?? ?? double?max_dist?=?0;?double?min_dist?=?100;?? ?? ?? for(?int?i?=?0;?i?<?descriptors_1.rows;?i++?)?? {?double?dist?=?matches[i].distance;?? ??if(?dist?<?min_dist?)?min_dist?=?dist;?? ??if(?dist?>?max_dist?)?max_dist?=?dist;?? }?? ?? printf("--?Max?dist?:?%f?\n",?max_dist?);?? printf("--?Min?dist?:?%f?\n",?min_dist?);?? ?? ?? ?? std::vector<?DMatch?>?good_matches;?? ?? for(?int?i?=?0;?i?<?descriptors_1.rows;?i++?)?? {?if(?matches[i].distance?<?2*min_dist?)?? ??{?good_matches.push_back(?matches[i]);?}?? }???? ?? ?? Mat?img_matches;?? drawMatches(?img_1,?keypoints_1,?img_2,?keypoints_2,??? ?????????????good_matches,?img_matches,?Scalar::all(-1),?Scalar::all(-1),??? ?????????????vector<char>(),?DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS?);??? ?? ?? imshow(?"Good?Matches",?img_matches?);??
在FLANN特征匹配的基礎上,還可以進一步利用Homography映射找出已知物體。具體來說就是利用findHomography函數利用匹配的關鍵點找出相應的變換,再利用perspectiveTransform函數映射點群。具體代碼如下:
[cpp]?view plain
?copy ?? std::vector<Point2f>?obj;?? std::vector<Point2f>?scene;?? ?? for(?int?i?=?0;?i?<?good_matches.size();?i++?)?? {?? ???? ??obj.push_back(?keypoints_1[?good_matches[i].queryIdx?].pt?);?? ??scene.push_back(?keypoints_2[?good_matches[i].trainIdx?].pt?);??? }?? ?? Mat?H?=?findHomography(?obj,?scene,?CV_RANSAC?);?? ?? ?? Point2f?obj_corners[4]?=?{?cvPoint(0,0),?cvPoint(?img_1.cols,?0?),?cvPoint(?img_1.cols,?img_1.rows?),?cvPoint(?0,?img_1.rows?)?};?? Point?scene_corners[4];?? ?? ?? for(?int?i?=?0;?i?<?4;?i++?)?? {?? ??double?x?=?obj_corners[i].x;??? ??double?y?=?obj_corners[i].y;?? ?? ??double?Z?=?1./(?H.at<double>(2,0)*x?+?H.at<double>(2,1)*y?+?H.at<double>(2,2)?);?? ??double?X?=?(?H.at<double>(0,0)*x?+?H.at<double>(0,1)*y?+?H.at<double>(0,2)?)*Z;?? ??double?Y?=?(?H.at<double>(1,0)*x?+?H.at<double>(1,1)*y?+?H.at<double>(1,2)?)*Z;?? ??scene_corners[i]?=?cvPoint(?cvRound(X)?+?img_1.cols,?cvRound(Y)?);?? }???? ??? ?? line(?img_matches,?scene_corners[0],?scene_corners[1],?Scalar(0,?255,?0),?2?);?? line(?img_matches,?scene_corners[1],?scene_corners[2],?Scalar(?0,?255,?0),?2?);?? line(?img_matches,?scene_corners[2],?scene_corners[3],?Scalar(?0,?255,?0),?2?);?? line(?img_matches,?scene_corners[3],?scene_corners[0],?Scalar(?0,?255,?0),?2?);?? ?? ?? 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 createTrackbar(?TrackbarName,?"Linear?Blend",?&alpha_slider,?alpha_slider_max,?on_trackbar?);??
第一個參數為字符串作為標簽,第二個參數為所在窗口的名字,第三個參數為存儲滑桿位置的值地址,其范圍為0~alpha_slider_max(第四個參數),最后一個參數為移動滑桿時調用的回調函數名。
OpenCV2.0版本加強了對視頻處理的支持,不再需要對一組連續的圖片進行處理,可以進行實時的圖像采集和記錄以及存儲。視頻的操作基本都被封裝在VideoCapture類中。打開視頻可以可以通過如下代碼實現:
[cpp]?view plain
?copy VideoCapture?captRefrnc(sourceReference);?? ?? VideoCapture?captUndTst;?? captUndTst.open(sourceCompareWith);??
其中sourceReference和sourceCompareWith為string型,為文件名。還可以通過isOpened函數檢測視頻是否成功打開。也可以調用release函數提前關閉視頻。還可以講VideoCapture放到Mat結構中,因為視頻流是一連串的,可以通過read函數或>>操作符逐幀的讀取,例如:
[cpp]?view plain
?copy Mat?frameReference,?frameUnderTest;?? captRefrnc?>>?frameReference;?? 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学习笔记(六)(七)(八)(九)(十)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。