圖像在OpenCV中都是通過Mat類來存儲的,Mat可以用來表示N維矩陣,當然用的最多的還是二維矩陣。
Mat類有兩部分組成:第一部分是頭信息,這些信息主要用來描述矩陣,比如矩陣維數ndims,rows,cols(這兩個成員變量主要用於二維矩陣,用來表示行數和列數),size,sizes, type,step等等;第二部分是data信息,這是一個指針,指向Mat中存儲的數據。
通過下面的代碼,我們創建一個二維矩陣,並打印出矩陣:
//創建一個5*5的2維矩陣,數據類型為8bit的無符號數,數據為3個通道,初始值都為(0,0,255)
cv::Mat M(5,5, CV_8UC3, cv::Scalar(0,0,255));
cout << "M = " << endl << " " << M << endl << endl;
這個矩陣的頭信息和數據如下圖所示:
step表示每一行占據的字節數目,包括padding數據,其中每行中的padding數據有點嚇到我了,我們只有15個uchar而已,沒想到step竟然這么大,而且每次運行程序還是變化的,真正的數據大小是 M.cols*M.elemSize() = 15,我們可以通過函數M.isContinuous()知道當前矩陣是否有padding數據。
沒有padding數據時候,我們可以把矩陣的data當一維數據處理,數據長度就是rows*cols*elemSize()。
下面我看看如何訪問矩陣中的元素,並進行操作:
1. 直接訪問data,簡單快速。
for(i=0; i< M.rows; i++)
{
for(j=0; j<M.cols*M.elemSize(); j++)
{
printf ("%d ", M.data[i*M.cols*M.elemSize() + j]);
}
printf("\n");
}
或者用下面的代碼:
uchar* p;
for( i = 0; i < M.rows; ++i)
{
//得到第i行的指針,等價於 p = M.data + i*M.step
p = M.ptr<uchar>(i);
for ( j = 0; j < M.cols; ++j)
{
printf (" %d %d %d",p[j*3], p[j*3+1],p[j*3+2]);
}
printf("\n");
或者我們也可以用at的方式得到數組元素,M.at<cv::Vec3b>(i,j)[2]得到元素中的第2個分量,如果M.at<uchar>(i,j),則只能取到元素的第一個分量。
//用at的方式訪問矩陣元素
for(i=0; i< M.rows; i++)
{
for(j=0; j<M.cols; j++)
{
printf ("%d %d %d ", M.at<cv::Vec3b>(i,j)[0],M.at<cv::Vec3b>(i,j)[1], M.at<cv::Vec3b>(i,j)[2]);
}
printf("\n");
}
}
2. 用c++迭代器的方式訪問。
cv::MatIterator_<cv::Vec3b> it, end;
for( it = M.begin<cv::Vec3b>(), end = M.end<cv::Vec3b>(); it != end; ++it)
{
printf("%d %d %d\n",(*it)[0], (*it)[1], (*it)[2]);
}
程序源碼:工程FirstOpenCV2。


