OpenCV影象畫素操作及效率分析
學習OpenCV也幾個月了,雖然對OpenCV有些瞭解,但是感覺基礎還是沒打實,在這在介紹一下OpenCV的畫素操作,以及OpenCV讀取影象的格式和讀取影象的效率分析。當然文章也有很多沒有介紹到的地方,希望大家多多指教,相互交流。
在計算機視覺應用中,對於影象內容的讀取分析是第一步,所以學習高效的處理影象是很有用的。一個影象有可能包含數以萬計的畫素,從根本上說影象就是一系列畫素值,所以OpenCV使用資料結構cv::Mat來表示影象。矩陣中每一個元素都代表一個畫素,對於灰度影象,畫素用8位無符號數,0表示黑色,255表示白色。對於彩色畫素而言,每個畫素需要三位這樣的8位無符號數來表示,即三個通道(R,G,B),矩陣則依次儲存一個畫素的三個通道的值,然後再儲存下一個畫素點。
cv::Mat中,成員變數cols代表影象的寬度(影象的列數),成員變數rows代表影象的高度(影象的行數),step代表以位元組為單位的影象的有效寬度,elemSize返回畫素的大小,畫素的大小 = 顏色大小(位元組)*通道數,比如三通道short型矩陣(CV_16SC3)的大小為2*3 = 6,畫素的channels方法返回影象的通道數,total函式返回影象的畫素數。
閒話少說直接介紹幾種讀取方式:
RGB影象的顏色數目是256*256*256,本文對影象進行量化,縮減顏色數目到256的1/8(即32*32*32)為目標,分別利用一下幾種方法實現,比較幾種方法的安全和效率。
1.ptr遍歷影象
cv::Mat中提供ptr函式訪問任意一行畫素的首地址,特別方便影象的一行一行的橫向訪問,如果需要一列一列的縱向訪問影象,就稍微麻煩一點。但是ptr訪問效率比較高,程式也比較安全,有越界判斷。
也可以使用:int nl= image.rows; //行數 int nc= image.cols * image.channels(); // 每行的元素個數,每行的畫素數*顏色通道數(RGB = 3) for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- data[i]= data[i]/div*div + div/2; // end of pixel processing ---------------- } // end of line }
for (int j=0; j<nl; j++) {
uchar* data= image.ptr<uchar>(j);
for (int i=0; i<nc; i++) {
// process each pixel ---------------------
*data++= *data/div*div + div/2;
// end of pixel processing ----------------
} // end of line
}
2.使用迭代器遍歷影象
cv::Mat 同樣有標準模板庫(STL),可以使用迭代器訪問資料。
用迭代器來遍歷影象畫素,可簡化過程降低出錯的機會,比較安全,不過效率較低;如果想避免修改輸入影象例項cv::Mat,可採用const_iterator。iterator有兩種呼叫方法,cv::MatIterator_<cv::Vec3b> it;cv::Mat_<cv::Vec3b>::iterator it;中間cv::Vec3b是因為影象是彩色影象,3通道,cv::Vec3b可以代表一個畫素。
// get iterators
cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();
for ( ; it!= itend; ++it) {
// process each pixel ---------------------
(*it)[0]= (*it)[0]/div*div + div/2;
(*it)[1]= (*it)[1]/div*div + div/2;
(*it)[2]= (*it)[2]/div*div + div/2;
// end of pixel processing ----------------
}
3.at方法遍歷
cv::Mat也是向量,可以使at方法取值,使用呼叫方法image.at<cv::Vec3b>(j,i),at方法方便,直接給i,j賦值就可以隨意訪問影象中任何一個畫素,其中j表示第j行,i表示該行第i個畫素。但是at方法效率是這3中訪問方法中最慢的一個,所以如果遍歷影象或者訪問畫素比較多時,建議不要使用這個方法,畢竟程式的效率還是比程式的可讀性要重要的。下面是完整的呼叫方法,其執行時間在下面會介紹。
int nl= image.rows; // number of lines
int nc= image.cols; // number of columns
for (int j=0; j<nl; j++) {
for (int i=0; i<nc; i++) {
// process each pixel ---------------------
image.at<cv::Vec3b>(j,i)[0]= image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;
image.at<cv::Vec3b>(j,i)[1]= image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;
image.at<cv::Vec3b>(j,i)[2]= image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;
// end of pixel processing ----------------
} // end of line
}
4.row(i),col(i)
cv::Mat提供image.row(i),和image.col(j)對影象整行和整列進行處理,處理比較方便,因為很少遇到,所以就沒有進行效率比較
程式程式碼如下(三通道):
result.row(0).setTo(cv::Scalar(0,0,0));//將第一行資料設為零 result.row(result.rows-1).setTo(cv::Scalar(0,0,0));//將最後一行資料設定為零 result.col(0).setTo(cv::Scalar(0,0,0));//將第一列資料設為零 result.col(result.cols-1).setTo(cv::Scalar(0,0,0));//將最後一列資料設為零
5.高效率影象遍歷迴圈
對於迭代的for迴圈,外面一層的迴圈次數越少速度越快,同樣是cols*rows*channels()次迴圈,使用nc = cols,nl = rows*channels(),與使用nc = cols*rows*channels,nl = 1,以及nc = cols,nl = rows,for函式最裡層執行三次顏色的處理。這三種方法最快的是第二種,第三種其次,最慢的是第一種. int nl= image.rows; // number of lines
int nc= image.cols * image.channels(); // total number of elements per line
if (image.isContinuous()) {
// then no padded pixels
nc= nc*nl;
nl= 1; // it is now a 1D array
}
int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
// mask used to round the pixel value
uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
for (int j=0; j<nl; j++) {
uchar* data= image.ptr<uchar>(j);
for (int i=0; i<nc; i++) {
// process each pixel ---------------------
*data++= *data&mask + div/2;
// end of pixel processing ----------------
} // end of line
}
6.位運算代替乘法和除法
int nl= image.rows; // number of lines
int nc= image.cols * image.channels(); // total number of elements per line
int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
// mask used to round the pixel value
uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
for (int j=0; j<nl; j++) {
uchar* data= image.ptr<uchar>(j);
for (int i=0; i<nc; i++) {
// process each pixel ---------------------
*data++= *data&mask + div/2;
// end of pixel processing ----------------
} // end of line
}
執行時間比較,以測試圖片為例,(Debug模式下的時間)
ptr函式的兩種方法的時間:using .ptr and [] =3.50202ms
using .ptr and * ++ =3.26124ms
迭代器方法:
using Mat_ iterator =143.06ms
at方法的執行時間:
using at =252.779ms
高效率迭代方法:
using .ptr and * ++ and bitwise (continuous) =2.68335ms
位運算方法:
using .ptr and * ++ and bitwise =2.59823ms
還有一些比較的函式方法,現在只給出執行時間:using .ptr and * ++ and modulo =3.78029ms
using .ptr and * ++ and bitwise =2.59823ms
using direct pointer arithmetic =2.57317ms
using .ptr and * ++ and bitwise with image.cols * image.channels() =22.864ms
using Mat_ iterator and bitwise =139.92ms
using MatIterator_ =185.996ms
using .ptr and * ++ and bitwise (continuous+channels) =2.11271ms
using input/output images =2.97717ms
using overloaded operators =2.7237ms
源影象:
量化處理結果 image1:
量化處理後的結果 image2:
相關推薦
OpenCV影象畫素操作及效率分析
學習OpenCV也幾個月了,雖然對OpenCV有些瞭解,但是感覺基礎還是沒打實,在這在介紹一下OpenCV的畫素操作,以及OpenCV讀取影象的格式和讀取影象的效率分析。當然文章也有很多沒有介紹到的地方,希望大家多多指教,相互交流。 在計
opencv影象畫素操作方法
影象容器Mat Mat和Matlab裡的陣列格式有點像,但一般是二維向量,如果是灰度圖,一般存放<uchar>型別;如果是RGB彩色圖,存放<Vec3b>型別。 單通道灰度圖資料存放格式: 多通道的影象中,每列並列存放通道數量的子列,如RGB三通
OpenCV二值化影象畫素操作
二值化影象畫素不是0就是255,資料型別為uchar。所以訪問方法是: // 這裡inputmat是二值化影象的mat inputmat.at<uchar>(y, x); 判斷是否為白色的方法: if (inputmat.at<uchar&g
opencv影象畫素值讀取
說到影象畫素,肯定要先認識一下影象中的座標系長什麼樣。 1. 座標體系中的零點座標為圖片的左上角,X軸為影象矩形的上面那條水平線;Y軸為影象矩形左邊的那條垂直線。該座標體系在諸如結構體Mat,Rect,
Android遊戲Graphics繪圖之影象畫素操作
我們在玩遊戲時經常會看到一些影象的特效,比如半透明等效果。要實現這些效果並不難,只需要對影象本身的畫素執行操作。Android中的 Bitmap同樣提供了操作畫素的方法,可以通過getPixels方法來獲得該影象的畫素並放到一個數組中,我們處理這個畫素陣列就可以了,最後
opencv 影象讀取顯示和畫素操作
從今天起,開始從頭系統學習下opencv,下面記錄下影象的基本操作: 1. 影象的讀取和顯示 Mat image = imread(imagePath, 1); 第二個引數表示圖片讀入的方式(
Python-OpenCV 處理影象(三):影象畫素點操作
https://segmentfault.com/a/1190000003742442 0x01. 畫素 有兩種直接操作圖片畫素點的方法: 第一種辦法就是將一張圖片看成一個多維的list,例如對於一張圖片im,想要操作第四行第四列的畫素點就直接 im[3,3] 就可以獲取到這個點的RGB值。 第二種就是
opencv對影象畫素進行操作
用Opencv對影象畫素進行操作大概有以下三種方式: 1. One using the Inbuilt macro 2. One using the pointer to the image data 3. Getting the raw data from the image. =============
運用opencv 讀取BMP影象畫素資訊 程式碼及實現
1. 環境:Win7(64位),opencv2.3,vs2010 2.程式碼: /////////////////////////////////////////////////////////////////////////////////////////////////
OpenCV學習筆記(三)之影象畫素的提取
提取影象的畫素及畫素索引 Mat src, dst; src = imread("mountainandwater.jpg"); //讀取影象 if (src.empty()) { qDebug()<<"can
opencv讀取影象畫素值讀取並儲存到txt檔案(二)灰度圖
#include "stdafx.h" #include"cv.h" #include <stdlib.h> #include <stdio.h> #include <math.h> #include <fstream> #include &l
opencv讀取影象畫素值讀取並儲存到txt檔案(一)RGB
#include “stdafx.h” #include"cv.h" #include <stdlib.h> #include <stdio.h> #include <math.h> #include #include #include “iost
openCV--訪問影象畫素的三個方法
方法一 指標訪問:C操作符[ ] 方法二 迭代器iterater 方法三 動態地址計算 訪問速度上,debug模式下 ,方法一 > 方法二 > 方法
常用的畫素操作演算法:影象加法、畫素混合、提取影象中的ROI
影象可以是看成是一個多維的陣列。讀取一張圖片,可以看成是讀入了一系列的畫素內容。這些畫素內容,按
OpenCV——修改影象畫素(隨心所欲)
這一節將講述OpenCV——修改影象畫素,根據自己需要新增特定的畫素部分 原圖如下,我們就是先在這個視訊流上新增一條直線段(有一定寬度的) 現在我們想新增一條,135行-455行,列350--360的直線段 #include<opencv2/opencv.hp
opencv中對影象畫素點訪問的三種方法利用程式進行解讀
程式碼放到自己的工程中,執行就可以的 #include <opencv2\opencv.hpp> #include <opencv2\core\core.hpp> #include <opencv2\highgui\highgui.hpp> #includ
opencv之訪問影象畫素
訪問畫素的三種方法 ①指標訪問:最快 ②迭代器iterator:較慢,非常安全,指標訪問可能出現越界問題 ③動態地址計算:更慢,通過at()實現。適用於訪問具體某個第i行,j列的畫素,而不適用遍歷畫素 Mat在記憶體中儲存形式 灰度圖的儲存形式 RGB的儲存形式 一般情況下,Mat
opencv之訪問影象畫素的 三種方法
訪問畫素的三種方法 ①指標訪問:最快 ②迭代器iterator:較慢,非常安全,指標訪問可能出現越界問題 ③動態地址計算:更慢,通過at()實現。適用於訪問具體某個第i行,j列的畫素,而不適用遍歷畫素 Mat在記憶體中儲存形式 灰度圖的儲存形式 RGB的儲存形式 一般情況下,M
opencv訪問影象畫素
(1) 假設你要訪問第k通道、第i行、第j列的畫素。 (2) 間接訪問: (通用,但效率低,可訪問任意格式的影象) 對於單通道位元組型影象: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); CvSc
opencv 通過指標訪問影象畫素值,輸出為空的問題
for (int i = 0; i < img_roi_gray_at.rows; ++i) { uchar* datatemp = img_roi_gray_at.ptr<uchar>(i);