cvmat矩陣資料結構是opencv的基礎資料型別,對於影象處理這種密級型運算,經常需要訪問,修改,設定其元素的值。opencv提供了很多優良的函式,能夠很簡單的實現上述功能。在《學習opencv》一書中,作者分別就簡單的方法,麻煩的方法,和恰當的方法對相關函式進行了講解,講得比較清晰。本文主要講解通過指標高效訪問cvmat元素的方法z及平時容易忽視的一些小問題。
1.關於元素資料型別
cvmat中資料型別由幾個部分構成 cv_(s|u|f)channels,s表示有符號的,u表示無符號的,f表示浮點數;比如cv_32f1,表示32位1通道浮點數;cv_8u3,表示8位無符號3通道整形;資料型別重要的原因在於
a.它決定了cvmat資料的分布,比如,若元素型別cv_8uc1(常用於灰度影象 ),那麼cvmat的資料排列是每行按照ggggggg(g表示乙個畫素的灰度值)的格式排列;若元素型別為cv_8uc3,則可以表示彩色影象,其行排列成為bgrbgrbgr(分別表示藍綠紅三個通道值,三個通道值表徵1個畫素)的形式;
b.在訪問其資料型別時,如何正確轉換成對應的資料型別指標;後面的例子會說到;
2.訪問cvmat中的元素
簡單的通過cv_mat_elem巨集,cvgetrealxd()函式即可實現,但是影象處理是計算密集型操作,這些函式雖然簡單易用,但是效率比較低。因此最常用的是採用指標來訪問cvmat中的元素。
cvmat結構中data結構對於指標訪問其元素非常重要.
其data成員為
uniondata;
由於是聯合體,因此在訪問時,
指標可以在這幾種型別的指標之間轉換。當然這還歸功於
cvmat中每行的位元組長度是固定的,成員step記錄了cvmat每行的位元組數。下面的**說明如何高效訪問矩陣元素。
cvmat* mat=cvcreatemat(5,3,cv_32fc1);//建立乙個5行3列的矩陣,元素型別為32位單通道浮點數;資料型別對於後面使用指標訪問矩陣元素非常重要。
cvzero(mat);
int row,col;
//下面的**給矩陣的每個元素賦值
for (row=0;rowheight;row++)
}//下面的3段**功能是一樣的,都是在控制台顯示各個元素的值
///code1
for (row=0;rowheight;row++)
}///code2
for (row=0;rowheight;row++)
std::cout<
} ///code 3
for (row=0;rowheight;row++)
std::cout<
}
///
用指標除了順序訪問cvmat中的元素外,還可以訪問任意位置的元素,當然前提是需要自己計算指標。比如:
for (row=0;rowheight;row++)
}
std::cout<
}cvreleasemat(&mat);//用完釋放相關資源
因此,對cvmat中的元素不要拘泥於書上提供的幾種方式,在程式效率很重要的情況下,可以合理使用指標結合step完美的訪問cvmat中的元素,當然,使用指標,也有缺點,出現錯誤不容易發現,自己曾經遭過道。
自己幾點體會:
(1):和作者前面提到的一樣,陣列的資料型別非常重要。其中通道數表明了資料的排列方式,資料型別對後面的訪問方式有很大影響;
(2):在cvmat中,最重要一點要理解的是step。
其有兩點非常重要;
第一:其是以位元組為單位的;
第二:對於指定的矩陣每行的位元組長度是固定的。
由這兩點可以引申出來兩種訪問方式
第一:對於以位元組為單位的這種形式,在上面的code1、code2表現的非常明顯。這裡對於不同型別的陣列,因為其所佔的空間大小不同,但是每行的位元組長度是固定的,這裡可以通過比例放縮,即除以sizeof(*),來準確定位;
第二:對於指定的矩陣每行的位元組長度是固定這種形式,在第乙個列子中表現明顯。這裡先用簡單的ptr定位,再進行強制轉換。因為是利用了固定的長度,這種一一對應的方式來進行定位,非常方便。這裡是把定位和操作分開進行的。
依據以上分析,下面給出簡單的總結(
cvmat* mat;
mat = cvcreatemat(9,10,cv_64fc3);//注意所申請矩陣元素的型別,不同的型別訪問操作方法不同,但類似可推導,以此為例。
opencv中的多通道矩陣cvmat元素的訪問方法總結如下:
1.mat(i,j,1):
*(mat->data.db
+ i*(mat->step/8) + 3*j);//.db為double資料型別,step型別為int,代表矩陣每行的
位元組數,因此要處以sizeof(double)
=8。
mat(i,j,2):
*(mat->data.db
+ i*(mat->step/8) + 3*j+1);
mat(i,j,3):
*(mat->data.db
+ i*(mat->step/8) + 3*j+2);
基本模式: *(mat->data.型別 + 行號*(該型別資料對應的一行的步長要按照該型別的長度來運算)+按照該型別來說的列數+所取的通道數)
2.mat(i,j,1):
((double*)
(mat->data.
ptr+i*mat->step))[3*j];//ptr的型別為uchar*,step型別為int,代表矩陣每行的位元組數。另外指標可以當做陣列名,因此可以這樣操作。
mat(i,j,2):
((double*)(mat->data.ptr
+i*mat->step))[3*j+1];
mat(i,j,3):
((double*)(mat->data.ptr+i*mat->step))[3*j+2];
基本模式:((強轉型別*)
(mat->data.
ptr+行號*mat->step))[3*列號+所取的通道數]
3.mat(i,j,1):
*((double*)
(mat->data.
ptr+i*mat->step) + 3*j );//根據以上也可以這樣
總之就是c語言中的指標操作啦,要注意指標的型別,以及step的單位是位元組就可以了。
4.運用cv_mat_elem巨集來訪問
mat(i,j,3): cv_mat_elem(mat,double,i,3*j+2)
該方法最方便。
自己的幾點體會:
(1):第一種方法是順序訪問的,但是這種最可能出問題。learning opencvp-46中說到,cvmat資料指標可以指向乙個大型陣列中的roi,所以無法保證資料逐行連續訪問。因此,這種容易出問題。
(2):第二種和第三種方法是每次重新計算起點,這種是精確的。
2 3 訪問CvMat資料塊(矩陣維度與通道)
通過opencv的函式來訪問矩陣的資料 cvget d,cvset d cvgetreal1d,cvgetreal2d,cvgetreal3d,cvgetrealnd cvget1d,cvget2d,cvget3d,cvge cvset d,也有相應的函式系列 這些函式的缺點是,效率低 real表示...
CvMat的宣告及元素訪問總結
最近處理矩陣資料,但是訪問cvmat元素時總會出現錯誤,所以重新翻了一下書,查詢了一些資料,這都屬於最基本的東西。opencv教程基礎篇 p48 1 分配矩陣 cvmat prepoint cvcreatemat 1,2,cv 32fc1 行,列,元素型別 而且用指標訪問元素賦值可以成立 1 pre...
OpenCV 矩陣資料訪問方法
cvmat矩陣資料結構是opencv的基礎資料型別,對於影象處理這種密級型運算,經常需要訪問,修改,設定其元素的值。opencv提供了很多優良的函式,能夠很簡單的實現上述功能。在 學習opencv 一書中,作者分別就簡單的方法,麻煩的方法,和恰當的方法對相關函式進行了講解,講得比較清晰。本文主要講解...