《OpenCV3程式設計入門》——5.1.5 訪問影象中畫素的三類方法(指標訪問、迭代器iterator、動態地址計算配合at元素)
阿新 • • 發佈:2018-11-30
目錄
OpenCV中,有三種方式訪問影象畫素:
- 指標訪問:C操作符[];
- 迭代器iterator
- 動態地址計算
上述方法在訪問速度上略有差異。debug模式下,差異非常明顯,在release模式下,差異就不太明顯。
下邊通過一組例子來說明這三種方法的使用,程式的作用是減少顏色的數量,比如原來的影象是256種顏色,我們希望將它變成64中顏色,只需要將原來的顏色除以4(整除)以後再乘以4即可。
主程式程式碼如下:
//---------------------------------【標頭檔案、名稱空間包含部分】-------------------------- // 描述:包含程式所使用的標頭檔案和名稱空間 //--------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <iostream> using namespace std; using namespace cv; //-----------------------------------【全域性函式宣告部分】----------------------------------- // 描述:全域性函式宣告 //------------------------------------------------------------------------------------------ //減少顏色 void colorReduce(Mat& inputImage, Mat& outputImage, int div); //--------------------------------------【main( )函式】--------------------------------------- // 描述:控制檯應用程式的入口函式,我們的程式從這裡開始執行 //----------------------------------------------------------------------------------------------- int main() { //【1】建立原始圖並顯示 Mat srcImage = imread("1.jpg"); imshow("原始影象", srcImage); //【2】按原始圖的引數規格來建立建立效果圖 Mat dstImage; dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());//效果圖的大小、型別與原圖片相同 //【3】記錄起始時間 double time0 = static_cast<double>(getTickCount()); //【4】呼叫顏色空間縮減函式 colorReduce(srcImage, dstImage, 32); //【5】計算執行時間並輸出 time0 = ((double)getTickCount() - time0) / getTickFrequency(); cout << "\t此方法執行時間為: " << time0 << "秒" << endl; //輸出執行時間 //【6】顯示效果圖 imshow("效果圖", dstImage); waitKey(0); }
1、指標訪問畫素
指標訪問畫素利用的是C語言中的操作符[]。這種方法最快,但是略有點抽象。實驗條件下單詞執行時間為0.00370487秒,程式碼如下:
//---------------------------------【colorReduce( )函式】--------------------------------- // 描述:使用【指標訪問:C操作符[ ]】方法版的顏色空間縮減函式 //---------------------------------------------------------------------------------------------- void colorReduce(Mat& inputImage, Mat& outputImage, int div) { //引數準備 outputImage = inputImage.clone(); //拷貝實參到臨時變數 int rowNumber = outputImage.rows; //行數 int colNumber = outputImage.cols*outputImage.channels(); //列數 x 通道數=每一行元素的個數 //雙重迴圈,遍歷所有的畫素值 for (int i = 0; i < rowNumber; i++) //行迴圈 { uchar* data = outputImage.ptr<uchar>(i); //獲取第i行的首地址 for (int j = 0; j < colNumber; j++) //列迴圈 { // ---------【開始處理每個畫素】------------- data[j] = data[j] / div*div; // ----------【處理結束】--------------------- } //行處理結束 } }
分析講解上述程式碼:
Mat類屬性:
- 公有變數cols和rows給出影象的寬和高
- channels():返回影象的通道數。灰度圖通道數為1,彩色通道數為3
- ptr()函式:得到任意行的首地址。ptr是一個模板函式,它返回第i行的首地址:uchar* data = outputImage.ptr<uchar>(i); //獲取第i行的首地址
每行的畫素值個數以下語句得到:
int colNumber = outputImage.cols*outputImage.channels(); //列數 x 通道數=每一行元素的個數
執行結果:
原始圖 | 效果圖 |
2、迭代器操作畫素
迭代器需要做的僅僅是獲得影象矩陣的begin和end,然後增加迭代直至從begin到end。將 * 操作符新增在迭代指標前,即可訪問當前指向的內容。
相比使用指標可能越界問題,迭代器絕對是非常安全的方法。
//-------------------------------------【colorReduce( )函式】-----------------------------
// 描述:使用【迭代器】方法版的顏色空間縮減函式
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
//引數準備
outputImage = inputImage.clone(); //拷貝實參到臨時變數
//獲取迭代器
Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>(); //初始位置的迭代器
Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>(); //終止位置的迭代器
//存取彩色影象畫素
for (; it != itend; ++it)
{
// ------------------------【開始處理每個畫素】--------------------
(*it)[0] = (*it)[0] / div*div; //藍色通道
(*it)[1] = (*it)[1] / div*div; //綠色通道
(*it)[2] = (*it)[2] / div*div; //紅色通道
// ------------------------【處理結束】----------------------------
}
}
執行結果:
原始圖 | 效果圖 |
3、動態地址計算
動態地址運算配合at方法。這種方法簡單明瞭,符合我們對畫素的認識。
//----------------------------------【colorReduce( )函式】-------------------------------
// 描述:使用【動態地址運算配合at】方法版本的顏色空間縮減函式
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
//引數準備
outputImage = inputImage.clone(); //拷貝實參到臨時變數
int rowNumber = outputImage.rows; //行數
int colNumber = outputImage.cols; //列數
//存取彩色影象畫素
for (int i = 0; i < rowNumber; i++)
{
for (int j = 0; j < colNumber; j++)
{
// ------------------------【開始處理每個畫素】--------------------
outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[0] / div*div; //藍色通道
outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[1] / div*div; //綠色通道
outputImage.at<Vec3b>(i, j)[2] = outputImage.at<Vec3b>(i, j)[2] / div*div; //紅是通道
// -------------------------【處理結束】----------------------------
} // 行處理結束
}
}
分析講解程式碼:
Mat:
- 成員函式at(int y, int x):用來儲存影象元素,但是必須在編譯期知道影象的資料型別。需要注意的是,一定要確保指定的資料型別和矩陣中的資料型別符合,因為at方法本身不會對任何資料型別進行轉換。
Vec3b:
- 一個影象的Mat會返回一個由三個8位陣列成的向量,,將其定義為Vec3b,即由三個unsigned char組成的向量,所以存取彩色影象畫素的程式碼可以寫出如下形式:
image.at<Vec3b>(i, j)[chanel] = value; //索引值channel標明瞭顏色通道號
執行結果:
原始圖 | 效果圖 |