opencv中提供了許多操作影象的函式,但是有時候我們需要直接操作畫素來實現我們的功能,這篇文章總結了opencv中常見的操作畫素的方法。
不同的影象有不同的畫素型別,不過對於不同的畫素型別,需要在模板引數傳入不同的值。首先畫素的資料型別包括cv_32u,cv_32s,cv_32f,cv_8u,cv_8uc3等,那這些型別都是什麼含義呢。第乙個數字表示位元數,第二個數字就表示c++中資料型別,如果還有後面兩個字元,這兩個字元表示通道數。例如對於cv_32u,表示具有32位元的unsigned int型別;對於cv_8uc3,表示具有8位元,並且有三個通道的unsigned char型別。對於這個型別,可以使用**type()**來獲取。
根據這些型別,又可以分為兩種,一種單通道的,一種多通道的。單通道的乙個畫素用乙個數值表示即可,而多通道的乙個畫素需要用多個畫素表示,最常用的三通道就需要rgb這三個數值來表示。那具體的通道順序是什麼呢?在opencv中,則是按bgr的順序來儲存的,用數字代替就是b用channels[0]來獲取,g用channels[1]來獲取,r用channels[2]來獲取。opencv的設計者就是這樣設計的,記住就好了。
cv::mat有個at()方法,可以訪問影象的單個畫素,同時at()方法又是乙個模板方法,所以在使用的時候需要傳入影象畫素的型別,而且這個型別不像c++中的運算型別一樣可以自動轉換,所以必須準確的傳入影象元素型別。
對於單通道元素來說,元素型別為unsigned char的情況下,可以這樣訪問
image.at(j,i)= value;
對於三通道元素彩色影象來說,那麼可以這樣
image.at(j,i)[channel]= value;
或者直接使用陣列賦值還更加方便
image.at(j,i) = cv::vec3b(a,b,c);
vec是opencv中的向量型別,它模板是vec,所以vec3b表示3個unsigned char組成的向量,vec2f表示由兩個float組成的向量,任何形式的向量都可以用這個vec來表示的。
mat_ 也是乙個模板類,注意它有乙個下劃線,以與mat作為區別。在實際使用中,mat_ 與 mat 的操作函式沒有多大區別,只不過mat_需要在建立時定義元素型別,以後再呼叫它的方法是就不需要再傳入資料的型別,而且還定義了乙個操作符()來獲取元素的位置。
cv::mat_image(image1);
image(20,30) = value;
或者使用
image.at(20,30) = value;
這兩個類之間的區別就是乙個是定義時指定型別,乙個是使用時指定型別,可以按照不同的情況來使用。
cv::mat還有個訪問指標的方法 ptr(),它能夠返回指定行的位址,然後就可以移動指標訪其他的畫素。
uchar *data = image.ptr(j);
上面**中data或獲取第j行的首位址。遍歷時,前三個位元組表示的是第乙個畫素的bgr值,注意bgr值順序,接下來三個位元組是第二個畫素的值。那畫素個數有限,想要停止怎麼辦?可以先提前獲取這一行中畫素的個數,然後到空指標了就停止這輪訪問,然後在換到其他行進行訪問。
int n = image.cols * image.channels();
用影象的列數與通道數相乘就獲得了影象的每行的畫素數。
而對於影象,有時候在記憶體中會為了對齊而對末尾的畫素有填充,而有時候沒有填充。可以使用iscontinue()來訪問影象是否有填充,對於沒有填充的影象,即連續的影象來說,便利的時候就可以只要一層迴圈就可以了,他會自己換行將影象變成一維的來處理。
create()方法的用處,這個方法先檢查mat物件是否已經分配了資料快取區,以及快取區的資料型別與需要的型別是否相等。如果相同則可以直接返回已分配好的快取區,否則重新建立乙個再返回。可以在需要另外單獨儲存時使用,判斷傳入的result image引數是否已經分配資料快取區。c++中的stl便設計了一套迭代器以用來訪問元素,opencv中也按照stl的設計原則設計了一套迭代器來訪問畫素,用法基本與stl類似。
對mat型別來說,他的迭代器型別可以使用matiterator_或者mat_::iterator型別,具體使用如下
cv::matiterator_ it;
或者cv::mat_::iterator it;
用這兩個迭代器便可以指定mat物件的迭代器,注意需要傳入模板引數。對迭代器的初始化與c++中的stl一致。
it = image.begin();
it = image.end();
遍歷也和前面指標一樣,從影象左上角第乙個畫素開始遍歷三個位元組,然後第二個位元組,依次遍歷,到第一行遍歷完後,就會到第二行來遍歷。不過我們也可以修改迭代器的位置,而不需要乙個乙個遍歷。
//跳過20個畫素
it += 20;
//跳到下一行同一位置
it += image.cols;
有時候不希望迭代器修改畫素的值,則可以使用常量迭代器,即有const屬性的迭代器,如果在遍歷過程中試圖修改畫素值則會報錯。
cv::matconstiterator_it;
或者cv::mat_::const_iterator it;
以上便是mat的迭代器的使用方法,在模板引數裡都需要傳入畫素型別,前面講過mat_物件只需要在定義時指定畫素型別,此後使用便不需要在指定型別,對於它的迭代器也是如此,請注意他與mat物件的區別。
cv::mat_image(image1);
cv::matiterator_ it = image.begin();
訪問影象畫素的幾種方法也介紹完了,考慮到程式的執行速度方面,通常at方法適合於訪問元素,但不適合遍歷元素;指標或者迭代器適合用於遍歷元素。 OpenCv C 凸包操作
什麼是凸包?簡單點就是在一幅影象裡面有很多點,而有一些點連成的形狀能夠把所有點包圍進去。使用opencv怎麼做?1 先將轉化為灰度影象 2 轉化為二值影象 3 找到的全部輪廓點 4 使用凸包api從全部輪廓點中找到最優輪廓點 5 連線凸包輪廓點 凸包使用的api是convexhull 下面看 inc...
OpenCV 操作畫素(訪問畫素值)
為構建計算機視覺應用程式,我們需要學會訪問影象的內容,有時也要修改或者建立影象。本章將講講如何操作影象的元素 即畫素 影象本質上就是由陣列組成的矩陣。opencv使用了cv mat結構來操作影象。矩陣中的每乙個元素表示乙個畫素。對灰度影象而言,畫素是8位無符號數 資料型別為unsigned char...
OpenGL畫素操作
簡單的opengl畫素操作 opengl提供了簡潔的函式來操作畫素 glreadpixels 讀取一些畫素。當前可以簡單理解為 把已經繪製好的畫素 它可能已經被儲存到顯示卡的視訊記憶體中 讀取到記憶體 gldrawpixels 繪製一些畫素。當前可以簡單理解為 把記憶體中一些資料作為畫素資料,進行繪...