opencv影象畫素操作方法
阿新 • • 發佈:2019-01-30
影象容器Mat
Mat和Matlab裡的陣列格式有點像,但一般是二維向量,如果是灰度圖,一般存放<uchar>型別;如果是RGB彩色圖,存放<Vec3b>型別。 單通道灰度圖資料存放格式:多通道的影象中,每列並列存放通道數量的子列,如RGB三通道彩色圖:
有一點需要注意:影象的通道順序是:BGR。通常情況記憶體足夠大的話影象的每一行是連續存放的,也就是在記憶體上影象的所有資料存放成一行,這中情況在訪問時可以提供很大方便。 好了,下面總結一下常見的訪問影象畫素的三種方法:使用at動態地址計算方式,使用iterator迭代器方式,使用ptr指標。先附程式碼:
執行結果如下:#include <iostream> #include<core/core.hpp> #include<highgui/highgui.hpp> using namespace cv; using namespace std; void colorReduceAt(Mat& srcImage, Mat& dstImageAt, int div); void colorReduceIterator(Mat& srcImage, Mat& dstImageIterator, int div); void colorReducePtr(Mat& srcImage, Mat& dstImagePtr, int div); int main() { Mat image=imread("e:\\kobe.jpg"); Mat mv[3]; split(image,mv); if(!image.data) { cout<<"you idiot!where did you hide kobe!"<<endl; system("pause"); return -1; } //宣告處理後圖像變數 Mat dstImageAt, dstImageIterator, dstImagePtr; dstImageAt = image.clone(); dstImageIterator = image.clone(); dstImagePtr = image.clone(); int div = 4; //宣告時間變數 double timeAt, timeIterator, timePtr; timeAt = static_cast<double>(getTickCount()); colorReduceAt(image, dstImageAt, div); timeAt = ((double)getTickCount() - timeAt) / getTickFrequency(); namedWindow("dstImageAt",CV_WINDOW_NORMAL); imshow("dstImageAt",dstImageAt); cout << "使用at()動態地址計算耗時:" << timeAt << endl << endl; timeIterator = static_cast<double>(getTickCount()); colorReduceIterator(image, dstImageIterator, div); timeIterator = ((double)getTickCount() - timeIterator) / getTickFrequency(); namedWindow("dstImageIterator",CV_WINDOW_NORMAL); imshow("dstImageIterator",dstImageIterator); cout << "使用iterator迭代器耗時:" << timeIterator << endl << endl; timePtr = static_cast<double>(getTickCount()); colorReducePtr(image, dstImagePtr, div); timePtr = ((double)getTickCount() - timePtr) / getTickFrequency(); namedWindow("dstImagePtr",CV_WINDOW_NORMAL); imshow("dstImagePtr",dstImagePtr); cout << "使用ptr指標耗時:" << timePtr << endl; //等待按鍵 waitKey(); return 0; } //使用at動態地址計算方式 void colorReduceAt(Mat& srcImage, Mat& dstImageAt, int div) { int rowNumber = dstImageAt.rows; //獲取影象行數 int colNumber = dstImageAt.cols; //獲取影象列數 //對每個畫素進行處理 for(int i = 0; i < rowNumber; i++) { for(int j = 0; j < colNumber; j++) { dstImageAt.at<Vec3b>(i,j)[0] = dstImageAt.at<Vec3b>(i,j)[0]/div*div; //B通道 dstImageAt.at<Vec3b>(i,j)[1] = dstImageAt.at<Vec3b>(i,j)[1]/div*div; //G通道 dstImageAt.at<Vec3b>(i,j)[2] = dstImageAt.at<Vec3b>(i,j)[2]/div*div; //R通道 } } } //使用iterator迭代器方式 void colorReduceIterator(Mat& srcImage, Mat& dstImageIterator, int div) { MatIterator_<Vec3b> imageIt = dstImageIterator.begin<Vec3b>(); //獲取迭代器初始位置 MatIterator_<Vec3b> imageEnd = dstImageIterator.end<Vec3b>(); //獲取迭代器結束位置 //對每個畫素進行處理 for(;imageIt != imageEnd; imageIt++) { (*imageIt)[0] = (*imageIt)[0]/div*div; //B通道 (*imageIt)[1] = (*imageIt)[1]/div*div; //G通道 (*imageIt)[2] = (*imageIt)[2]/div*div; //R通道 } } //使用ptr指標 void colorReducePtr(Mat& srcImage, Mat& dstImagePtr, int div) { int rowNumber = dstImagePtr.rows; //獲取影象矩陣行數 int colNumber = dstImagePtr.cols*dstImagePtr.channels(); //三通道影象矩陣列樹=影象列數x通道數 for(int i = 0; i < rowNumber; i++) { uchar* pixelPtr = dstImagePtr.ptr<uchar>(i); //獲取矩陣每行首地址指標 for(int j = 0; j < colNumber; j++) pixelPtr[j] = pixelPtr[j] / div * div; } }
並且發現,使用ptr方式訪問畫素用時最少。
參考:
https://yq.aliyun.com/articles/9300
http://www.cnblogs.com/zjgtan/archive/2013/04/06/3002962.html
http://blog.csdn.net/keith_bb/article/details/53071133
後來新發現一篇比較全的博文介紹:http://blog.csdn.net/xiaowei_cqu/article/details/19839019