opencv中Mat類型數據操作與遍歷


 

Mat作為opencv中一種數據類型常常用來存儲圖像,相對與以前的IplImgae類型來說,Mat類型省去了人工的對內存的分配與釋放,轉而自動分配釋放。Mat Class主要包括兩部個數據部分:一個是matrix header(包括matrix的大小尺寸,儲存方法,儲存地址等等..),另一個是指向存儲像素值的矩陣的指針。

Opencv中對Mat的復制分為兩種,

Mat A, C;                                 // creates just the header parts
A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // here we'll know the method used (allocate matrix)

Mat B(A);                                 // Use the copy constructor

C = A;                                    // Assignment operator


Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries

上面一類僅僅新建了matrix header,對與像素矩陣A,B,C共有,修改其中一項的像素值,其他的也都會改變,可以理解為他們提供了對相同底層數據的不同讀取方法。 這么做的好處是為了減少計算成本。

如果僅僅想操作其中的一部分像素,可以創建一個讀取部分的header matrix

當然Opencv也提供深度復制的方法

Mat F = A.clone();
Mat G;
A.copyTo(G);

 

 

Mat的創建

cv::Mat::Mat Constructor:

    Mat M(2,2, CV_8UC3, Scalar(0,0,255));
    cout << "M = " << endl << " " << M << endl << endl;

  

 

 cv::Mat::create function:

    M.create(4,4, CV_8UC(2));
    cout << "M = "<< endl << " "  << M << endl << endl;

  

MATLAB style initializer: cv::Mat::zeros , cv::Mat::ones , cv::Mat::eye 

    Mat E = Mat::eye(4, 4, CV_64F);
    cout << "E = " << endl << " " << E << endl << endl;
    Mat O = Mat::ones(2, 2, CV_32F);
    cout << "O = " << endl << " " << O << endl << endl;
    Mat Z = Mat::zeros(3,3, CV_8UC1);
    cout << "Z = " << endl << " " << Z << endl << endl;

  

 對於一些小的kernel可以自定義如下:

    Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cout << "C = " << endl << " " << C << endl << endl;

  

 

 

在對圖像進行分析及操作時往往需要進行遍歷或對某一區域的像素值進行操作。總結了一下比較常用的有以下幾種方法。

1.利用ptr指針訪問Mat像素

for(int j = 1; j < myImage.rows - 1; ++j)
{
    const uchar* previous = myImage.ptr<uchar>(j - 1);
    const uchar* current  = myImage.ptr<uchar>(j    );
    const uchar* next     = myImage.ptr<uchar>(j + 1);

    uchar* output = Result.ptr<uchar>(j);

    for(int i = nChannels; i < nChannels * (myImage.cols - 1); ++i)
    {
        *output++ = saturate_cast<uchar>(5 * current[i]
                     -current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]);
    }
}

2.使用 Mat::at 函數 

int main()
{    
    Mat img = imread("lena.jpg");
    imshow("Lena Original", img);
    if(img.channel() > 1)
   {
      for (int row = 0; row < img.rows; row++)
     {
        for (int col = 0; col < img.cols; col++)
        {    
            /* 注意 Mat::at 函數是個模板函數, 需要指明參數類型, 因為這張圖是具有紅藍綠三通道的圖,
               所以它的參數類型可以傳遞一個 Vec3b, 這是一個存放 3 個 uchar 數據的 Vec(向量). 這里
               提供了索引重載, [2]表示的是返回第三個通道, 在這里是 Red 通道, 第一個通道(Blue)用[0]返回 */
            if(img.at<Vec3b>(row, col)[2] > 128)
                img.at<Vec3b>(row, col) = Vec3b(255, 255, 255);
        }
     }

   }
   else
  {
        for (int row = 0; row < img.rows; row++)
     {
        for (int col = 0; col < img.cols; col++)
        {    
           
            if(img.at<Vec3b>(row, col) > 128)
                img.at<Vec3b>(row, col) = 255;
        }
     }

  }
   
    imshow("Lena Modified", img);
    cvWaitKey();
    return 0;
}

  

 


免責聲明!

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



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