OpenCV C++ API 矩陣常用運算


最近和Samuel成功地搭建了基於編碼結構光的三維重建系統,這項技術應該說已經是很成熟的了,代碼我們也從網上download下來學習,當然自己也重寫了一遍。

除了系統校准,實際操作時整個流程分為圖像解碼和基於三角學計算三維坐標兩大塊,在不同地方加入不同的filter以及一些recover的過程。之前的代碼沿用了OpenCV C的API。

為了配合部門其他組員,同時本着與時俱進的精神,這兩天主要就是將之前的代碼換成C++的API,同時借這個小項目來熟悉一下OOP。(盡管這個很沒有必要)

 

對於C++的API,最常用的一個變量類型就是Mat,命名空間cv,用來存儲矩陣數據。

聲明一個矩陣頭(習慣上我看成指針)

cv::Mat a;

 聲明並初始化

int row = 3;
int col = 4;
cv::Mat a(row, col, CV_8UC1, cv::Scalar(0));

輸出整個矩陣可以直接用cout。如果是3通道的矩陣,可以用CV_8UC3,賦值中Scalar設置相應的初始化值,這時候輸出的矩陣一共還是3行,但是有12(=4*3)列,但是矩陣本身的數據成員cols依然是4。

遍歷元素

cv::Mat a(5, 4, CV_8UC1, cv::Scalar(0));

for (int r = 0; r < a.rows; r++)
{
    for (int c = 0; c < a.cols; c++)
    {
        std::cout<<(int)a.ptr<uchar>(r)[c]<<std::endl;
    }
}

(int)a.ptr<uchar>(r)[c],這句代碼調用了a的數據成員ptr(指針),指明類型是uchar(與CV_8U)對應,a.ptr<uchar>(r)指向a的第r+1行(下標從零開始),a.ptr<uchar>(r)[c]指向a的第r+1行第c+1列元素並取值,因為指針是指向uchar類型,所以顯示時先將其轉換為int。

常用的一些對應關系:CV_8U --- uchar, CV_16U --- ushort, CV_32F --- float, CV_64F --- double

如果是3通道,例如CV_32FC3,就在a.ptr<float>(r)的基礎上偏移c*3+i,其中i = 0 ,1,2,就是說矩陣有c列,每一列包含3小列,每個元素是一個包含了3個float數據的東西,但是指針是指向float類型的,所以發生偏移時按照float的長度來計算,因此橫跨c列實際上要偏移c*3個float占據的長度,再加上i,就可以訪問某一個元素中第一、第二和第三個通道中的數據。

cv::Mat x(5, 4, CV_32FC3, cv::Scalar(0.0, 1.1, 2.2));

for (int r = 0; r < x.rows; r++)
{
    for (int c = 0; c < x.cols; c++)
    {
    for (int i = 0; i < 3; i++)
    {
      std::cout<<
a.ptr<float>(r)[c*3+i]<<std::endl;
    } } }

當然更一般的寫法是通過x.channel()的方法獲取當前矩陣的通道數。

 

常用的矩陣聲明/初始化

cv::Mat a;
a.create(5,4,CV_32FC3);  //生成5行4列,float類型3通道矩陣,這個方法不能賦值
a.setTo(cv::Scalar(0.0,1.0,2.0)); //可以配合這個函數來使用

注意當賦值的通道數少於目標通道數時,默認補零,譬如上述代碼中如果cv::Scalar(0.0,1.0,2.0)變為cv::Scalar(0.0,1.0),則矩陣所有元素的第三通道的值都是0.0。

OpenCV關於矩陣的操作大多數都允許帶掩模進行。譬如

 

cv::Mat a;
a.create(5,4,CV_8UC1);
a.setTo(1, mask);

 

其中mask是一個和a同size的矩陣,mask中非零的位置,a的對應位置的元素會被set為1,其他部分不變。mask默認值是全非零,也就是說默認對a的所有元素都執行操作。

 

矩陣的display,可以將8U的矩陣當作圖像顯示出來(實際上16U也可以)。直接使用imshow()即可,類似C API中的cvImageShow().

cv::Mat k(500,500,CV_8UC1,128);
cv::imshow("k display",k);
cv::waitKey(0);
cv::destroyWindow("k display");

waitKey用於等待用戶按鍵,destroyWindow用於銷毀指定窗口。

 

矩陣元素級的常用操作

cv::Mat a(3,2,CV_8UC1,cv::Scalar(127));
cv::Mat b(3,2,CV_8UC1,cv::Scalar(128));
cv::Mat mask(3,2,CV_8UC1,255);//默認全體操作
...//修改mask獲得指定掩模
double alpha;
double beta;
cv::Mat c;
cv::add(a,b,c,mask); // a+b 元素級相加,結果放到c,下面的類似
cv::scaleAdd(a, alpha, b, c, mask); // a*alpha+b, 元素級相加,其中一個矩陣帶縮放
cv::addWeighted(a, alpha, b beta, c, mask); // a*alpha+b*beta, 元素級相加,兩個矩陣分別帶縮放系數 (還可以帶偏移gamma)
cv::subtract(a,b,c,mask); // 元素級想減
cv::abs(a,c); // 取絕對值
cv::absdiff(a,b,c); // 元素級相減取絕對值 (個人很好奇為何不是absDiff而是全小寫)
cv::multiply(a,b,c,mask); // 元素級乘法
cv::divide(a,b,c,mask); // 元素級除法
//類似的操作還有log,sqrt,exp,pow,min,max

cv::compare(a,b,c, cv::CMP_GT); // 元素級比較大小,結果存放在c中,條件滿足則為255,否則為0,就是說c是一個元素類型CV_8UC1的矩陣
//條件關系 CMP_GT 大於 --- CMP_GE 大於等於 --- CMP_LT 小於 --- CMP_LE 小於等於 --- CMP_EQ 等於 --- CMP_NE 不等於

//元素級邏輯運算
cv::bitwise_or(a,b,c,mask);
//類似的還有bitwise_and等,注意這個不僅僅是元素級,還是位運算,例如a某個元素是128,b對應位置的元素是0,則它們進行bitwise_or的結果,對應位置是128
//如果b對應位置的元素是1,那么結果對應位置就是129(因為128最后一位是0,和1的最后一位(也就是1)相或后得到1,128的前邊的位數都保留了,得到129)
//同理如果a的元素是129,b對應元素是1,那么結果該位置還是129

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM