1. 程式人生 > >opencv中遍歷每一個畫素點進行處理

opencv中遍歷每一個畫素點進行處理

轉載:http://blog.csdn.net/wwwsssZheRen/article/details/74315591

1.用動態地址操作畫素:

  1. Mat srcImage(100, 100, CV_8UC3, Scalar(200,20,100));  
  2. imshow("顯示影象", srcImage);  
  3. int rowNumber = srcImage.rows;  
  4. int colNumber = srcImage.cols;  
  5. for (int i = 0; i <rowNumber; i++)  
  6. {  
  7.     for (int j = 0; j <colNumber; j++)  
  8.     {  
  9.         if (srcImage.at<
    Vec3b>(i, j)[0] > 180)   
  10.         {  
  11.             srcImage.at<Vec3b>(i, j)[0] = 0;            
  12.         }  
  13.         if (srcImage.at<Vec3b>(i, j)[1] <50)   
  14.         {  
  15.             srcImage.at<Vec3b>(i, j)[1] = 255;  
  16.         }  
  17.         if (srcImage.at<Vec3b>(i, j)[2] <120)   
  18.         {  
  19.             srcImage.at<Vec3b>(i, j)[2] = 0;  
  20.         }  
  21.     }  
  22. }  
  23. imshow("處理後的影象", srcImage);  
cv::mat的成員函式: .at(int y, int x)可以用來存取影象中對應座標為(x,y)的元素座標。(Mat類中的cols和rows給出了影象的寬和高。而成員函式at(int x, int y)可以用來存取影象的元素。)由於at方法本身不會對任何資料型別進行轉化,故一定要確保指定的資料型別和矩陣中的資料型別相符合。

假設提前已知一幅影象img的資料型別為 unsigned char型灰度圖(單通道),對畫素的賦值操作為image.at<uchar>(i,j) = value。而對於彩色影象,每個畫素由三個部分構成:藍色通道、綠色通道和紅色通道(BGR),對於一個包含彩色影象的Mat,會返回一個由三個8位陣列組成的量。OpenCV將此型別定義為Vec3b,即由三個unsigned char組成的向量。這也解釋了為什麼存取彩色影象畫素的程式碼可以寫成:

image.at<Vec3b>(i,j)[channel] = value;

以下是統計canndy後的0畫素點與255畫素點之間的數量的比值:

  1. #define _CRT_SECURE_NO_WARNINGS  
  2. #include <iostream>
  3. #include <opencv2/opencv.hpp>
  4. using namespace std;  
  5. using namespace cv;  
  6. int main()   
  7. {  
  8.     Mat graySrc = imread("../../11.bmp", 0);  
  9.     Mat canImage;  
  10.     Canny(graySrc, canImage, 60, 120);  
  11.     int PicZero = 0;  
  12.     int PicFull = 0;  
  13.     for (int i = 0; i <graySrc.rows; ++i)   
  14.     {  
  15.         for (int j = 0; j <graySrc.cols; ++j)   
  16.         {  
  17.             if (canImage.at<unsigned char>(i, j) == 0)   
  18.             {  
  19.                 PicZero++;  
  20.             }  
  21.             else  
  22.             {  
  23.                 PicFull++;  
  24.             }     
  25.         }  
  26.     }  
  27.     cout << "0畫素點比255畫素點的比值為" << (double)PicZero / PicFull <<endl;  
  28.     system("pause");  
  29. }  


2.用指標的方法:

有時候我們需要遍歷Mat中的每一個畫素點,並且對畫素點進行處理,這裡以影象所有畫素點都減去div(div屬於int型別)

  1. void colorReduce(Mat& inputImage, Mat& outputImage, int div)  
  2. {  
  3.     // 引數準備  
  4.     outputImage = inputImage.clone();  
  5.     int rowNumber = outputImage.rows;  
  6.     int colNumber = outputImage.cols*outputImage.channels();  
  7.     for (int i = 0; i <rowNumber; i++)  
  8.     {  
  9.         // 獲取第i行的首地址  
  10.         uchar* data = outputImage.ptr<uchar>(i);  
  11.         for (int j = 0; j <colNumber; j++)  // 列迴圈  
  12.         {  
  13.             // 開始處理每一個畫素值,每一個畫素值都減去div  
  14.             data[j] = data[j] - div;  
  15.         }  
  16.     }  
  17. }  

也可以寫成如下形式:

  1. Mat inverseColor1(Mat srcImage)   
  2. {  
  3.     Mat tempImage = srcImage.clone();  
  4.     int row = tempImage.rows;  
  5.     int col = tempImage.cols * tempImage.channels();  
  6.     for (int i = 0; i <row; ++i)   
  7.     {  
  8.         const unsigned char* sourcedata = srcImage.ptr(i);  
  9.         unsigned char* data = tempImage.ptr(i);  
  10.         for (int j = 0; j <col; j++)  
  11.         {  
  12.             data[j] = sourcedata[j] - div;  
  13.         }  
  14.     }  
  15.     return tempImage;  
  16. }  
此時是定義了兩個指標型別: const unsigned char*和 unsigned char*,其中const unsigned char* 中的內容只能夠被讀取,不能被修改

特別需要注意的是:Mat中每一行元素的個數=列數*通道數

如需要列印M,

  1. Mat M(3, 2, CV_8UC3, Scalar(0, 0, 255));  
  2. cout <<M<<endl;  
列印結果為:驗證了每一行元素的個數為: 列數*通道數

另外需要注意的是:Mat 除了擁有成員變數cols,rows,成員函式channels()之外,還提供了ptr函式可以返回得到影象任意行的首地址。

3.用迭代器Matlterator_:

        Matlterator_是Mat資料操作的迭代器,:begin()表示指向Mat資料的起始迭代器,:end()表示指向Mat資料的終止迭代器。迭代器方法是一種更安全的用來遍歷影象的方式,首先獲取到資料影象的矩陣起始,再通過遞增迭代實現移動資料指標。

  1. Mat inverseColor4(Mat srcImage)   
  2. {  
  3.     Mat tempImage = srcImage.clone();  
  4.     // 初始化原影象迭代器  
  5.     MatConstIterator_<Vec3b>srcIterStart = srcImage.begin<Vec3b>();  
  6.     MatConstIterator_<Vec3b>srcIterEnd = srcImage.end<Vec3b>();  
  7.     // 初始化輸出影象迭代器  
  8.     MatIterator_<Vec3b>resIterStart = tempImage.begin<Vec3b>();  
  9.     MatIterator_<Vec3b>resIterEnd = tempImage.end<Vec3b>();  
  10.     while (srcIterStart != srcIterEnd)   
  11.     {  
  12.         (*resIterStart)[0] = 255 - (*srcIterStart)[0];  
  13.         (*resIterStart)[1] = 255 - (*srcIterStart)[1];  
  14.         (*resIterStart)[2] = 255 - (*srcIterStart)[2];  
  15.         srcIterStart++;  
  16.         resIterStart++;  
  17.     }  
  18.     return tempImage;  
  19. }