OpenCV學(xué)習(xí)筆記(六)——對(duì)XML和YAML文件實(shí)現(xiàn)I/O操作
1. XML、YAML文件的打開和關(guān)閉
XML\YAML文件在OpenCV中的數(shù)據(jù)結(jié)構(gòu)為FileStorage,打開操作例如:
[cpp]?view plain
?copy string?filename?=?"I.xml";?? FileStorage?fs(filename,?FileStorage::WRITE);?? \\...?? fs.open(filename,?FileStorage::READ);??
文件關(guān)閉操作會(huì)在FileStorage結(jié)構(gòu)銷毀時(shí)自動(dòng)進(jìn)行,但也可調(diào)用如下函數(shù)實(shí)現(xiàn)
[cpp]?view plain
?copy fs.release();??
2.文本和數(shù)字的輸入和輸出
寫入文件使用 ?<< ?運(yùn)算符,例如:
[cpp]?view plain
?copy fs?<<?"iterationNr"?<<?100;??
讀取文件,使用 >> 運(yùn)算符,例如
[cpp]?view plain
?copy int?itNr;?? fs["iterationNr"]?>>?itNr;?? itNr?=?(int)?fs["iterationNr"];??
3. OpenCV數(shù)據(jù)結(jié)構(gòu)的輸入和輸出,和基本的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要注意在第一個(gè)元素前加上“[”,在最后一個(gè)元素前加上"]"。例如:
[cpp]?view plain
?copy fs?<<?"strings"?<<?"[";??? fs?<<?"image1.jpg"?<<?"Awesomeness"?<<?"baboon.jpg";?? fs?<<?"]";???
對(duì)于map結(jié)構(gòu)的操作使用的符號(hào)是"{"和"}",例如:
[cpp]?view plain
?copy fs?<<?"Mapping";??? fs?<<?"{"?<<?"One"?<<?1;?? fs?<<?"Two"?<<?2?<<?"}";??
讀取這些結(jié)構(gòu)的時(shí)候,會(huì)用到FileNode和FileNodeIterator數(shù)據(jù)結(jié)構(gòu)。對(duì)FileStorage類的[]操作符會(huì)返回FileNode數(shù)據(jù)類型,對(duì)于一連串的node,可以使用FileNodeIterator結(jié)構(gòu),例如:
[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. 讀寫自己的數(shù)據(jù)結(jié)構(gòu)
這部分比較復(fù)雜,參考最后的實(shí)例中的MyData結(jié)構(gòu)自己領(lǐng)悟吧
最后,我這里上一個(gè)實(shí)例,供大家參考。
源文件里填入如下代碼:
[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;?? }??
編譯后,在命令行進(jìn)入到文件目錄,執(zhí)行test test.xml,運(yùn)行結(jié)果如下,
生成一個(gè)test . xml文件,內(nèi)容如下:
[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學(xué)習(xí)筆記(七)——圖像處理之濾波器ImgProc
先介紹幾個(gè)最基本的核濾波器相關(guān)的類
2D圖像濾波器基礎(chǔ)類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) ); 相關(guān)的調(diào)用函數(shù)為getLinearFilter、getMorphologyFilter
單行核濾波器基礎(chǔ)類BaseRowFilter:dst(x,y) = F(src(x,y), src(x+1,y),...src(x+width-1,y));相關(guān)的調(diào)用函數(shù)為getLinearRowFilter、getMorphologyRowFilter
單列核濾波器基礎(chǔ)類BaseColumnFilter:dst(x,y) = F(src(x,y), src(x,y+1),...src(x,y+width-1));相關(guān)的調(diào)用函數(shù)為getColumnSumFilter、getLinearColumnFilter、getMorphologyColumnFilter
類FilterEngine:該類可以應(yīng)用在對(duì)圖像的任意濾波操作當(dāng)中,在OpenCV濾波器函數(shù)中扮演著很重要的角色,相關(guān)的函數(shù)有createBoxFitler、createDerivFitlter、createGaussianFilter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter
基于這些類有一些基本的濾波器bilateralFilter、blur、boxFilter
還有一些形態(tài)學(xué)操作如:dilate、erode、morphologyEx
還有基于核和圖像卷積的濾波器filter2D
還有一些典型的濾波器如GaussianBlur、medianBlur、Laplacian、pyrMeanShiftFiltering、sepFilter2D
還有Sobel、Scharr運(yùn)算符
其他一些函數(shù)有borderInterpolate、buildPyramid、copyMakeBorder、createBoxFilter、createDirivFilter、createGaussianFliter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter、getDerivKernels、getGaussianKernel、getKernelType、getStructuringElement、pyrDown、pyrUp
還老版本的濾波器cvSmooth
這里介紹一下我使用Laplacian濾波的心得,這個(gè)函數(shù)的第三個(gè)參數(shù)為輸出的圖像的深度,注意經(jīng)過拉普拉斯算子處理后得到的值是有正有負(fù)的,所以輸出圖像的深度最好為輸入圖像深度的2倍,才能有效防止數(shù)據(jù)溢出,如必須要使用8位的數(shù)據(jù),可以再使用函數(shù)convertScaleAbs處理。而且要注意使用的拉普拉斯算子掩膜的中心系數(shù)為負(fù)。
OpenCV學(xué)習(xí)筆記(八)——圖像處理之直方圖ImgProc
直方圖histograms也是圖像處理中經(jīng)常用到的一種手段。新版本對(duì)直方圖不再使用之前的histogram的形式,而是用統(tǒng)一的Mat或者M(jìn)atND的格式來存儲(chǔ)直方圖,可見新版本Mat數(shù)據(jù)結(jié)構(gòu)的優(yōu)勢(shì)。先介紹下其相關(guān)的函數(shù)
calcHist、calcBackProject、compareHist、EMD、equalizeHist。除了這幾個(gè)常用的函數(shù)以為,還有一些c函數(shù)寫的直方圖類CvHistogram的相關(guān)操作,如下:cvCalcBackProjectPatch、cvCalcProbDensity、cvClearHist、cvCopyHist、cvCreateHist、cvGetHistValue_XD、cvGetMinMaxHistValue、cvMakeHistHeaderForArray、cvNormalizeHist、QueryHistValue_XD、cvReleaseHist、cvSetHistBinRanges、cvThreshHist、cvCalcPGH
calcHist函數(shù)為計(jì)算圖像的直方圖,使用方法如下:
[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為輸入圖像的個(gè)數(shù),channels為用來計(jì)算直方圖的通道列表,mask為掩膜矩陣,不為空的時(shí)候,只計(jì)算arrays中的掩膜區(qū)域的直方圖,hist為輸出的直方圖矩陣,dims為直方圖矩陣的維度,histSize為每一維直方圖矩陣的大小,ranges為每一維直方圖元素的取值范圍,是一個(gè)2維數(shù)組的地址,uniform為直方圖是否為統(tǒng)一模式,統(tǒng)一模式下會(huì)拉伸為range的大小,accumulate為累計(jì)標(biāo)志,方便直方圖的更新,不需要重新計(jì)算
舉幾個(gè)實(shí)例方便大家理解:
對(duì)于圖像為灰度圖,調(diào)用方式如下:
[cpp]?view plain
?copy int?histSize?=?255;?? float?ranges[]?=?{0,?255};?? const?float*?histRange?=?{ranges};?? calcHist(&img,?1,?0,?Mat(),?hist,?1,?&histSize,?&histRange);??
直方圖的歸一化
已經(jīng)不再適合cvNormalizeHist這個(gè)函數(shù)了,只需要用對(duì)矩陣的歸一化函數(shù)
normalize
就可以實(shí)現(xiàn)了。
直方圖均衡化函數(shù)為equalizeHist,這個(gè)函數(shù)比較簡(jiǎn)單,這里就不詳細(xì)介紹了
直方圖的比較函數(shù)為compareHist,函數(shù)返回值為兩矩陣的相似程度,相似度衡量的辦法目前支持4種
– CV_COMP_CORREL Correlation相關(guān)系數(shù),相同為1,相似度范圍為[ 1, 0 )
– CV_COMP_CHISQR Chi-Square卡方,相同為0,相似度范圍為[ 0, +inf )
– CV_COMP_INTERSECT Intersection直方圖交,數(shù)越大越相似,,相似度范圍為[ 0, +inf )
– CV_COMP_BHATTACHARYYA Bhattacharyya distance做常態(tài)分別比對(duì)的Bhattacharyya 距離,相同為0,,相似度范圍為[ 0, +inf )
計(jì)算反向投影圖函數(shù)為
calcBackProject
。所謂反向投影圖就是一個(gè)概率密度圖。calcBackProject的輸入為圖像及其直方圖,輸出與待跟蹤圖像大小相同,每一個(gè)像素點(diǎn)表示該點(diǎn)為目標(biāo)區(qū)域的概率。這個(gè)點(diǎn)越亮,該點(diǎn)屬于物體的概率越大。關(guān)于反向直方圖,可以參考一下這篇文章
http://blog.163.com/thomaskjh@126/blog/static/370829982010112810358501/
,這個(gè)函數(shù)使我們利用特征直方圖尋找圖片中的特征區(qū)域變得更加方便容易。這里舉一個(gè)比較常用的例子:如果已經(jīng)有一個(gè)膚色的特征直方圖,則可以在待檢測(cè)圖像中利用直方圖方向投影圖找出圖片中的膚色區(qū)域。
OpenCV學(xué)習(xí)筆記(九)——2維特征Feature2D
基于特征點(diǎn)的圖像匹配是圖像處理中經(jīng)常會(huì)遇到的問題,手動(dòng)選取特征點(diǎn)太麻煩了。比較經(jīng)典常用的特征點(diǎn)自動(dòng)提取的辦法有Harris特征、SIFT特征、SURF特征。
先介紹利用SURF特征的特征描述辦法,其操作封裝在類SurfFeatureDetector中,利用類內(nèi)的detect函數(shù)可以檢測(cè)出SURF特征的關(guān)鍵點(diǎn),保存在vector容器中。第二部利用SurfDescriptorExtractor類進(jìn)行特征向量的相關(guān)計(jì)算。將之前的vector變量變成向量矩陣形式保存在Mat中。最后強(qiáng)行匹配兩幅圖像的特征向量,利用了類BruteForceMatcher中的函數(shù)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;?}??
當(dāng)然,進(jìn)行強(qiáng)匹配的效果不夠理想,這里再介紹一種FLANN特征匹配算法。前兩步與上述代碼相同,第三步利用FlannBasedMatcher類進(jìn)行特征匹配,并只保留好的特征匹配點(diǎn),代碼如下:
[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特征匹配的基礎(chǔ)上,還可以進(jìn)一步利用Homography映射找出已知物體。具體來說就是利用findHomography函數(shù)利用匹配的關(guān)鍵點(diǎn)找出相應(yīng)的變換,再利用perspectiveTransform函數(shù)映射點(diǎn)群。具體代碼如下:
[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特征檢測(cè),在計(jì)算機(jī)視覺中,通常需要找出兩幀圖像的匹配點(diǎn),如果能找到兩幅圖像如何相關(guān),就能提取出兩幅圖像的信息。我們說的特征的最大特點(diǎn)就是它具有唯一可識(shí)別這一特點(diǎn),圖像特征的類型通常指邊界、角點(diǎn)(興趣點(diǎn))、斑點(diǎn)(興趣區(qū)域)。角點(diǎn)就是圖像的一個(gè)局部特征,應(yīng)用廣泛。harris角點(diǎn)檢測(cè)是一種直接基于灰度圖像的角點(diǎn)提取算法,穩(wěn)定性高,尤其對(duì)L型角點(diǎn)檢測(cè)精度高,但由于采用了高斯濾波,運(yùn)算速度相對(duì)較慢,角點(diǎn)信息有丟失和位置偏移的現(xiàn)象,而且角點(diǎn)提取有聚簇現(xiàn)象。具體實(shí)現(xiàn)就是使用函數(shù)cornerHarris實(shí)現(xiàn)。
除了利用Harris進(jìn)行角點(diǎn)檢測(cè),還可以利用Shi-Tomasi方法進(jìn)行角點(diǎn)檢測(cè)。使用函數(shù)goodFeaturesToTrack對(duì)角點(diǎn)進(jìn)行檢測(cè),效果也不錯(cuò)。也可以自己制作角點(diǎn)檢測(cè)的函數(shù),需要用到cornerMinEigenVal函數(shù)和minMaxLoc函數(shù),最后的特征點(diǎn)選取,判斷條件要根據(jù)自己的情況編輯。如果對(duì)特征點(diǎn),角點(diǎn)的精度要求更高,可以用cornerSubPix函數(shù)將角點(diǎn)定位到子像素。
OpenCV學(xué)習(xí)筆記(十)——圖形交互和媒體接口HighGUI
OpenCV提供一個(gè)功能強(qiáng)大的UI接口,可以在MFC、Qt、WinForms、Cocoa等平臺(tái)下使用,甚至不需要其他的平臺(tái)。新版本的HighGUI接口包括:
創(chuàng)建并控制窗口,該窗口可以顯示圖片并記錄其內(nèi)容
為窗口添加了trackbars控件,可以方便利用鼠標(biāo)進(jìn)行控制而不是之前版本的只能利用鍵盤
讀寫硬盤和內(nèi)存的圖片
讀取攝像頭的視頻、讀寫視頻文件
先來介紹UI,包括函數(shù)createTrackbar、getTrackbarPos、setTrackbarPos、imshow、namedWindow、destroyWindow、destroyAllWindows、MoveWindow、ResizeWindow、SetMouseCallback、waitKey。這些函數(shù)保證了圖像的基本處理、tarckbar的控制和鼠標(biāo)鍵盤的響應(yīng)
介紹一下讀寫圖像視頻的函數(shù):圖像相關(guān)的函數(shù)有imdecode、imencode、imread、imwrite。讀取視頻相關(guān)為VideoCapture類,負(fù)責(zé)捕捉文件和攝像頭的視頻,該類內(nèi)有成員函數(shù)VideoCapture、open、isOpened、release、grab、retrieve、read、get、set,寫視頻的類為VideoWriter,類內(nèi)有成員函數(shù)VideoWriter、open、isOpened、write
新版本還為Qt做了新函數(shù),這里就不介紹了,有興趣的朋友可以自己看一下參考手冊(cè)的第四章第三節(jié)。
這里介紹幾個(gè)常用的新功能,首先介紹一下添加滑桿控件Trackbar。調(diào)用函數(shù)為:
[cpp]?view plain
?copy createTrackbar(?TrackbarName,?"Linear?Blend",?&alpha_slider,?alpha_slider_max,?on_trackbar?);??
第一個(gè)參數(shù)為字符串作為標(biāo)簽,第二個(gè)參數(shù)為所在窗口的名字,第三個(gè)參數(shù)為存儲(chǔ)滑桿位置的值地址,其范圍為0~alpha_slider_max(第四個(gè)參數(shù)),最后一個(gè)參數(shù)為移動(dòng)滑桿時(shí)調(diào)用的回調(diào)函數(shù)名。
OpenCV2.0版本加強(qiáng)了對(duì)視頻處理的支持,不再需要對(duì)一組連續(xù)的圖片進(jìn)行處理,可以進(jìn)行實(shí)時(shí)的圖像采集和記錄以及存儲(chǔ)。視頻的操作基本都被封裝在VideoCapture類中。打開視頻可以可以通過如下代碼實(shí)現(xiàn):
[cpp]?view plain
?copy VideoCapture?captRefrnc(sourceReference);?? ?? VideoCapture?captUndTst;?? captUndTst.open(sourceCompareWith);??
其中sourceReference和sourceCompareWith為string型,為文件名。還可以通過isOpened函數(shù)檢測(cè)視頻是否成功打開。也可以調(diào)用release函數(shù)提前關(guān)閉視頻。還可以講VideoCapture放到Mat結(jié)構(gòu)中,因?yàn)橐曨l流是一連串的,可以通過read函數(shù)或>>操作符逐幀的讀取,例如:
[cpp]?view plain
?copy Mat?frameReference,?frameUnderTest;?? captRefrnc?>>?frameReference;?? captUndTst.open(frameUnderTest);??
read函數(shù)只能逐幀的抓取,如果要抓取某一幀,可以成對(duì)的調(diào)用grab函數(shù)和retrieve函數(shù)。get函數(shù)可以獲取視頻相關(guān)信息。set函數(shù)可以控制視頻的一些值,比如是指視頻的當(dāng)前位置或幀數(shù)。
可以使用VideoWriter類創(chuàng)建新視頻,其open,isOpened函數(shù)調(diào)用方法類似,write函數(shù)或<<運(yùn)算符向視頻寫入內(nèi)容,可以使用split函數(shù)和merge函數(shù)單獨(dú)調(diào)整RGB通道的值
今日,被一個(gè)網(wǎng)友指出,說OpenCV以前提供的讀寫功能采用VFW,效率低下且有些格式支持不好。而 OpenCV 2.0 內(nèi)置了videoInput Library,可以自動(dòng)在VFW和DirectShow間切換。videoInput是老外寫的功能強(qiáng)大的開源視頻處理庫(kù)。是一個(gè)第三方庫(kù),2.0~2.2的版本專門有一個(gè)3rdparty對(duì)該庫(kù)進(jìn)行支持,而在最新的2.3版本中,已經(jīng)講videoInput庫(kù)集成到highgui中了,想使用它的話,只需要在cmake中設(shè)置宏WITH_VIDEOiNPUT=OFF/ON即可。
以后有新學(xué)到的東西都會(huì)陸續(xù)補(bǔ)充進(jìn)來。
from: http://blog.csdn.net/yang_xian521/article/category/910716
總結(jié)
以上是生活随笔為你收集整理的OpenCV学习笔记(六)(七)(八)(九)(十)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。