1. 程式人生 > >OpenCV入門教程(5)-Mat類之Mat_類

OpenCV入門教程(5)-Mat類之Mat_類

Mat_類是對 Mat 類的一個包裝,其定義如下:

template<typename _Tp> class Mat_ : public Mat
{
public:
    //只定義了幾個方法
    //沒有定義新的屬性
};

這是一個非常輕量級的包裝,既然已經有 Mat 類,為何還要定義一個 Mat_?下面我們看這段程式碼:

Mat M(600, 800, CV_8UC1);
for( int i = 0; i < M.rows; ++i)
{
    uchar * p = M.ptr<uchar>(i);
    for( int j = 0; j < M.cols; ++j )
    {
        double
d1 = (double) ((i+j)%255); M.at<uchar>(i,j) = d1; double d2 = M.at<double>(i,j);//此行有錯 } }

在讀取矩陣元素時,以及獲取矩陣某行的地址時,需要指定資料型別。這樣首先需要不停地寫“”,讓人感覺很繁瑣,在繁瑣和煩躁中容易犯錯,如上面程式碼中的錯誤,用 at()獲取矩陣元素時錯誤的使用了 double 型別。這種錯誤不是語法錯誤,因此在編譯時編譯器不會提醒。在程式執行時,at()函式獲取到的不是期望的(i,j)位置處的元素,資料已經越界,但是執行時也未必會報錯。這樣的錯誤使得你的程式忽而看上去正常,忽而彈出“段錯誤”,特別是在程式碼規模很大時,難以查錯。
如果使用 Mat_類,那麼就可以在變數宣告時確定元素的型別,訪問元素時不再需要指定元素型別,即使得程式碼簡潔,又減少了出錯的可能性。上面程式碼可以用 Mat_實現,實現程式碼如下面例程裡的第二個雙重 for 迴圈。

#include <iostream>
#include "opencv2/opencv.hpp"
#include <stdio.h>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
    Mat M(600, 800, CV_8UC1);
    for( int i = 0; i < M.rows; ++i)
    {
        //獲取指標時需要指定型別
        uchar * p = M.ptr<uchar>(i);
        for
( int j = 0; j < M.cols; ++j ) { double d1 = (double) ((i+j)%255); //用 at()讀寫畫素時,需要指定型別 M.at<uchar>(i,j) = d1; //下面程式碼錯誤,應該使用 at<uchar>() //但編譯時不會提醒錯誤 //執行結果不正確,d2 不等於 d1 double d2 = M.at<double>(i,j); } } //在變數宣告時指定矩陣元素型別 Mat_<uchar> M1 = (Mat_<uchar>&)M; for( int i = 0; i < M1.rows; ++i) { //不需指定元素型別,語句簡潔 uchar * p = M1.ptr(i); for( int j = 0; j < M1.cols; ++j ) { double d1 = (double) ((i+j)%255); //直接使用 Matlab 風格的矩陣元素讀寫,簡潔 M1(i,j) = d1; double d2 = M1(i,j); } } return 0; }