O'Reilly 的《Learning OpenCV》的例子果然還是過(guò)時(shí)了。書(shū)中使用的還是第一代的基于C的代碼。于是一邊照著書(shū)本,一邊對(duì)照著官方手冊(cè),打算將書(shū)中的示例代碼用OpenCV2的C++API重寫(xiě)一遍。
今天的內(nèi)容有:
其中的頁(yè)碼對(duì)應(yīng)清華大學(xué)出版社翻譯的第一版《學(xué)習(xí)OpenCV》。
USAGE 宏和 namespace cliout 均在文件 cppcommon.hpp,相關(guān)代碼如下:
// cppcommon.hpp #ifndef CPPCOMMON_HPP #define CPPCOMMON_HPP namespace cliout { using std::cout; using std::endl; using std::cerr; #define USAGE(expr, options) \ do {\ if (!(expr)) {\ cerr << "Usage: " << argv[0]\ << " " << options\ << endl;\ return 1;\ }\ } while (0) } #endif |
SCPP_XXX_ASSERT 宏在文件 scpp_assert.hpp下,就不給出了,不過(guò)可以使用下面的定義使代碼正常運(yùn)行:
// scpp_assert.hpp #ifndef SCPP_ASSERT_HPP #define SCPP_ASSERT_HPP #include <assert.h> #define SCPP_ASSERT(expr, msg) assert(expr) #define SCPP_TEST_ASSERT(expr, msg) assert(expr) #endif /*SCPP_ASSERT_HPP*/ |
第二代中,包含頭文件"opencv2/opencv.hpp“將使用opencv的所有功能,也可以有選擇性地包含需要的文件"opencv2/highgui.hpp“。
儲(chǔ)存圖像的數(shù)據(jù)類型不再是 IplImage 的指針, 使用 cv::Mat 即可。
讀取圖像的函數(shù)改為:
cv::imread( const string & FileName, int flag) |
其中,可選的 flag 有
創(chuàng)建窗口的函數(shù)改為
cv::namedWindow( const string & windowName, int flag) |
其中,可選的 flag 有
CV_WINDOW_NORMAL or CV_WINDOW_AUTOSIZE: normal 模式下可以手動(dòng)調(diào)整窗口大小, 而 auto 模式(默認(rèn))下窗口將自動(dòng)適應(yīng)圖像大小,無(wú)法手動(dòng)調(diào)整。(gtk3, qt 下可用)
CV_WINDOW_FREERATIO or CV_WINDOW_KEEPRATIO: free_ratio 模式下調(diào)整圖像時(shí)不考慮其比率, 而 keep_ratio 模式將保持圖像的縮放比率 (qt下可用)
CV_GUI_NORMAL or CV_GUI_EXPANDED: expanded 模式下將顯示額外的工具欄和按鈕(NOTE:僅qt下可用)
由 cvWaitKey() 改為 cv::waitKey(), 變化不大
在C++API下,終于不用手動(dòng)釋放資源了。記得在MFC下繪圖的時(shí)候,因?yàn)橥涐尫臘C,導(dǎo)致程序運(yùn)行時(shí) Stack Overflow,調(diào)試了兩天才找出bug,實(shí)在不是什么美好的回憶。
示例 2-1 代碼如下:
// Exp 02-01 Display Image in C++ style #include "opencv2/opencv.hpp" #include "cppcommon.hpp" #include <string> int main( int argc, char *argv[]) { using namespace cliout; using std::string; USAGE(argc==2, "ImageFile" ); string winName = "C++ Style OpenCV2!" ; cv::namedWindow(winName, CV_WINDOW_NORMAL); // show grayscale image cv::Mat img = cv::imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); cv::imshow(winName, img); cv::waitKey(0); // show default color type image img = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR); // default cv::imshow(winName, img); cv::waitKey(0); } |
同樣,視頻捕獲的數(shù)據(jù)也從指針改成類 cv::VideoCapture 了。構(gòu)造函數(shù)接受的參數(shù)有:
由capture類輸出圖像的方法現(xiàn)在可以使用重載的 operator>>(cv::Mat imageOut) ,示例如下:
cv::Mat img; cv::VideoCapture cap( "test.avi" ); cap >> img; |
grab()方法將抓取下一幀,retrieve()函數(shù)則將抓取的幀解碼,如果抓取失敗, retrieve()將返回 false。
double get(int PropertyID)和 bool set(int PropID, double value) 可以用來(lái)設(shè)置類內(nèi)部的屬性,可選的屬性ID如下:
CV_CAP_PROP_POS_MSEC 當(dāng)前位置(單位:ms)
CV_CAP_PROP_POS_FRAMES 當(dāng)前位置(單位:幀數(shù),從0開(kāi)始計(jì))
CV_CAP_PROP_POS_AVI_RATIO 當(dāng)前位置(單位:比率, 0表示開(kāi)始,1表示結(jié)尾)
CV_CAP_PROP_FRAME_WIDTH 幀寬度
CV_CAP_PROP_FRAME_HEIGHT 幀高度
CV_CAP_PROP_FPS 幀速率
CV_CAP_PROP_FOURCC 4-字符表示的視頻編碼(如:’M‘, ’J‘, ’P‘, ’G‘)
CV_CAP_PROP_FRAME_COUNT 總幀數(shù)
CV_CAP_PROP_FORMAT retrieve().調(diào)用返回的矩陣格式
CV_CAP_PROP_MODE 后端變量指示的當(dāng)前捕獲的模式
CV_CAP_PROP_BRIGHTNESS 明亮度(僅用于攝像頭)
CV_CAP_PROP_CONTRAST 對(duì)比度(僅用于攝像頭)
CV_CAP_PROP_SATURATION 飽和度(僅用于攝像頭)
CV_CAP_PROP_HUE 色調(diào)(僅用于攝像頭)
CV_CAP_PROP_GAIN 增益(僅用于攝像頭)
CV_CAP_PROP_EXPOSURE 曝光度 (僅用于攝像頭)
CV_CAP_PROP_CONVERT_RGB 是否應(yīng)該將圖像轉(zhuǎn)化為RGB圖像(布爾值)
CV_CAP_PROP_WHITE_BALANCE 白平衡(暫不支持 v2.4.3)
CV_CAP_PROP_RECTIFICATION 立體攝像頭標(biāo)定 (目前僅支持 DC1394 v 2.x 后端)
相關(guān)函數(shù)有:
int createTrackbar( const string& trackbarname, const string& winname, int * value, int count, TrackbarCallback onChange=0, void * userdata=0) int getTrackbarPos( const string& trackbarname, const string& winname) void setTrackbarPos( const string& trackbarname, const string& winname, int pos) |
構(gòu)造函數(shù)中,value指示當(dāng)前的滾動(dòng)條坐標(biāo),count指示坐標(biāo)的最大值(最小值為0),onChange指向坐標(biāo)改變時(shí)的回調(diào)函數(shù),而userdata將作為參數(shù)傳遞給回調(diào)函數(shù)。
回調(diào)函數(shù)的簽名如下:
void foo( int pos, void * userdata) |
其中,pos指示滾動(dòng)條當(dāng)前坐標(biāo)。
// Exp 02-02~03 Video Player #include "opencv2/opencv.hpp" #include "cppcommon.hpp" #include "scpp_assert.hpp" #include <string> void onTrackbarChange( int pos, void * userdata) { cv::VideoCapture cap = * (cv::VideoCapture *) userdata; cap.set(CV_CAP_PROP_POS_FRAMES, pos); } int main( int argc, char *argv[]) { using namespace cliout; using std::string; USAGE(argc==2, "VideoFile" ); string winName = "Video Player" ; cv::namedWindow(winName); cv::VideoCapture cap(argv[1]); SCPP_ASSERT(cap.isOpened(), "Can not open Video Capture from file: " << argv[1]); int frameCount = cap.get(CV_CAP_PROP_FRAME_COUNT); SCPP_ASSERT(frameCount > 0 && cap.grab(), "Bad Video File: " << argv[1] << "with frame count " << frameCount); int fps = cap.get(CV_CAP_PROP_FPS); int mspf = 1000 / fps; string trackbarName = "Progress" ; int pos = 0; cv::createTrackbar( /* tbName = */ trackbarName, /* winName = */ winName, /* current pos = */ &pos, /* max pos = */ frameCount, // void callback(int pos, void* userdata) /* callback = */ onTrackbarChange, /* userdata = */ ( void *) &cap ); cv::Mat frame; while (pos < frameCount) { cap >> frame; cv::imshow(winName, frame); cv::setTrackbarPos(trackbarName, winName, ++pos); char c = cv::waitKey(mspf); if (std:: tolower (c) == 'q' ) break ; } } |
第一代中的 cvSmooth() 已經(jīng)被舍棄,取而代之的是 cv::blur(), cv::GaussianBlur() 等一系列函數(shù)。下面僅講解GaussianBlur(),其原型如下:
cv::GaussianBlur(InputArray src, OutputArray dest, cv::Size ksize, int SigmaX, int SigmaY) |
InputArray 和 OutputArray 可以看作是OpenCV 對(duì) Mat 類型進(jìn)行讀/寫(xiě)權(quán)限設(shè)置以防止誤操作,這個(gè)工作是自動(dòng)完成的,用戶只需要填入Mat類型的參數(shù)即可,不需要自行定義 InputArray 和 OutputArray 類型的變量。
其中,ksize 指示核(kernel)的大小, 如果Size被設(shè)置為0, 核的尺寸將由 SigmaX 和 SigmaY 自動(dòng)推導(dǎo)。
示例代碼如下:
// Exp 02-04 Gaussian Smooth #include "opencv2/opencv.hpp" #include "cppcommon.hpp" #include "scpp_assert.hpp" #include <string> int main( int argc, char *argv[]) { using namespace cliout; using cv::Mat; using std::string; USAGE(argc == 2, "ImageFile" ); Mat imgIn = cv::imread(argv[1]); SCPP_ASSERT(!imgIn.empty(), "Bad Image File: " << argv[1]); // Do some Image Processing Mat imgOut; cv::GaussianBlur(imgIn, imgOut, /* Kernel Size = */ cv::Size(0,0), // if set to 0, it's computed from sigma /* Sigma X = */ 3, /* Sigma Y = */ 3); // Display string winIn ( "Original Image" ), winOut( "After Gaussion Blur" ); cv::namedWindow(winIn, CV_WINDOW_NORMAL); cv::imshow(winIn, imgIn); cv::waitKey(0); cv::namedWindow(winOut, CV_WINDOW_NORMAL); cv::imshow(winOut, imgOut); cv::waitKey(0); } |
聯(lián)系客服