《學(xué)習(xí)OpenCV》(中文版)學(xué)習(xí)筆記

概述

POCT-IR圖像識別算法中拋開實驗室相關(guān)的內(nèi)容秋麸,其圖像處理部分都是使用OpenCV來完成。通過學(xué)習(xí)《OpenCV3編程入門》撼嗓,可以更好的在POCT-IR中使用OpenCV,同時也可以對項目中可以提升的點提出一些方案。

通過對這本書的閱讀懒震,深刻地感受到對圖像進行操作歸根結(jié)底就是對圖像中的特定像素點進行處理,最終得到目標(biāo)圖像嗤详。在OpenCV3數(shù)以百計的API法中个扰,有些API以單個像素點作為特征量的變換單位,來修改圖像內(nèi)容葱色,例如:濾波递宅、灰度值變換等。還有一些API以一定范圍內(nèi)的像素點作為特征量的變化單位,來對圖像進行變換办龄,例如邊緣檢測烘绽、仿射變化等。

這篇學(xué)習(xí)筆記以《學(xué)習(xí)OpenCV》書籍中的API為基礎(chǔ)土榴,結(jié)合實踐中的思考诀姚,對OpenCV3進行介紹,加深記憶的同時也希望能夠?qū)χ笫褂肙penCV3的小伙伴起到一定的指引作用玷禽。

全文按照以下三個方面對OpenCV學(xué)習(xí)的內(nèi)容進行整理:

Mat結(jié)構(gòu)赫段、基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)

OpenCV基本API介紹及使用

1. MAT類介紹、基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

貫穿OpenCV始終的就是Mat類矢赁,通過了解Mat的結(jié)構(gòu)及內(nèi)存分配方式糯笙,將極大的推進我們對OpenCV的學(xué)習(xí)。而一些基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)有助于提高代碼的可讀性和實用性(Point)撩银。

1.1 MAT到底是什么给涕?

內(nèi)存管理

在OpenCV1.0時代,Mat(IplImage*)是存放圖像的數(shù)據(jù)結(jié)構(gòu)额获、基本的圖像容器够庙。在使用的過程中,需要手動管理內(nèi)存空間抄邀,否則會造成內(nèi)存泄漏耘眨。

從OpenCV2.0開始,為了減少手動管理內(nèi)存空間的操作境肾,使用引用計數(shù)的方式將Mat對象進行內(nèi)存管理剔难。

內(nèi)部定義結(jié)構(gòu)

Mat類可以將其分為Header部分和Pointer部分,Header部分主要存放矩陣的大小奥喻,存儲方式偶宫,存儲地址等信息;而Pointer部分主要存儲指向像素值的指針环鲤。在復(fù)制的過程中產(chǎn)生大量計算開銷是復(fù)制Pointer造成的纯趋,所以在Clone過程中只復(fù)制header相關(guān)信息,減少內(nèi)存開銷冷离。

Mat核心成員定義介紹

// 指針结闸,指向存放Pointer的內(nèi)存

uchar* data; int rows, cols;

// 矩陣中每個元素?fù)碛兄档膫€數(shù)

int channels() const;

// 每個元素的位數(shù)

int depth() const;

// 矩陣的維度

int dims;

// 矩陣中每個元素的大小

size_t elemSize() const;

// 矩陣元素的類型

CV_8UC3、CV_16UC2 int type() const;

// 定義了矩陣的布局

size_t step1(int i=0) const;

...

上述部分介紹了Mat的核心成員變量酒朵,通過這些成員變量也大致能夠知道Mat存儲圖像的方式,涉及到如何進行初始化及這些成員變量的運用扎附,在之后的章節(jié)中通過案例及初始化MAT對象對成員變量進一步的認(rèn)識蔫耽。

注:在剛開始閱讀OpenCV相關(guān)文獻的時候,有些文獻會將MAT介紹為結(jié)構(gòu)體,在另一些文章中將Mat介紹為類匙铡,一開始對于各文章中的介紹孰是孰非很難有定論图甜,但是因為其需要手動管理內(nèi)存空間的機制,或者是使用引用計數(shù)的方式管理內(nèi)存鳖眼,根據(jù)OC的值類型和引用類型的相關(guān)知識(結(jié)構(gòu)體是值類型存在棧中系統(tǒng)會自動清理內(nèi)容黑毅、類是引用類型需要運用ARC、MRC機制進行內(nèi)容管理)類比钦讳,確信Mat是一個類矿瘦。如果有更權(quán)威的文獻能夠啪啪打臉,請指正~

1.2 初始化MAT對象

寫這篇文章的提綱時愿卒,一直在糾結(jié)需不需要將這部分內(nèi)容放進來缚去,只是關(guān)于Mat初始化并不是很值得放入到文章中。最后考慮加入這部分內(nèi)容琼开,首先確實Mat類是OpenCV核心中的核心易结,其次對筆記之后內(nèi)容得介紹起到承上啟下的作用。

Mat構(gòu)造函數(shù)

創(chuàng)建方法

UMat(int rows, int cols, int type,const Scalar& s,UMatUsageFlags usageFlags = USAGE_DEFAULT);

Mat mat(2, 2, CV_8UC3, Scalar::all(255, 0, 0));

說明介紹

rows = 2, cols = 2;代表創(chuàng)建一個2*2的矩陣柜候;

type = CV_8UC3搞动;描述為使用8位unsigned char型,每個像素由3個元素組成3通道渣刷。

注 :每個像素最多的通道數(shù)為4鹦肿,除了BGR外加入alpha,而最少為單通道飞主,即灰度值狮惜。

Scalar = Scalar::all(0, 0, 0));描述為每個元素的值為(255, 0, 0),注意不同于常使用的RGB顯示碌识,在OpenCV中采用BGR的方式即第一通道是B碾篡,第二通道是G,第三通道是R筏餐。

Mat mat(2, 2, CV_8UC3, Scalar::all(255, 0, 0));整體描述為創(chuàng)建了一個2*2像素值為藍(lán)色的Mat對象开泽。

更多初始化Mat對象的方法

UMat(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);

UMat(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);

//! constucts 2D matrix and fills it with the specified value _s.

UMat(Size size, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT);

//! constructs n-dimensional matrix

UMat(int ndims, const int* sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); UMat(int ndims, const int* sizes, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT);

//! copy constructor UMat(const UMat& m);

//! creates a matrix header for a part of the bigger matrix

UMat(const UMat& m, const Range& rowRange, const Range& colRange=Range::all()); UMat(const UMat& m, const Rect& roi);

UMat(const UMat& m, const Range* ranges);

UMat(const UMat& m, const std::vector& ranges);

通過imread返回Mat對象

創(chuàng)建方法

Mat imread(const String& filename,int flags = IMREAD_COLOR);

Mat srcImage = imread("../海賊王2.jpg");

說明介紹

filename指的是文件的絕對路徑,imread對文件格式有一定的要求(bmp魁瞪、jpg穆律、jpeg等)

flags指的是打開文件的方式,通過修改flags的值导俘,直接將圖片進行處理峦耘。例如圖片設(shè)置為單通道IMREAD_GRAYSCALE,或者減少圖片的色值IMREAD_REDUCED_COLOR_2 (色值減少為之前的1/2)等旅薄;

注:將圖片色值減少為原來的1/2的原理是將每個通道上的值除以2取整辅髓,在2,相當(dāng)于去除掉奇數(shù)值。 偽代碼實現(xiàn): outputImage.at(i, j)[0] = outputImage.at(i, j)[0]/2*2; IMREAD_REDUCED_COLOR_4洛口; IMREAD_REDUCED_COLOR_8同理矫付,在損失一定色值的情況下提高存儲效率。

在接下來的筆記中大多數(shù)都是以imread函數(shù)創(chuàng)建Mat對象第焰。

2. OpenCV基本API的介紹及使用

上一節(jié)中對Mat及初始化進行了介紹买优,相信已經(jīng)迫不及待的想要將OpenCV的圖像處理運用到實例中去,在本節(jié)中將會介紹一個色值衰減的案例和畫線的案例挺举,作為切入點來感受一下神奇的OpenCV杀赢。雖然這些例子都相對簡單,但通過這些例子還是可以窺探出在使用OpenCV進行圖像處理時的基本操作步驟:

獲取Mat對象.

在Mat對象中根據(jù)需求尋找特征像素點.

對特征像素點進行修改豹悬,使之獲取新的Mat對象.

重復(fù)2葵陵、3操作獲取新的Mat對象,直到Mat對象符合最終結(jié)果.

輸出圖像.

2.1 減少圖片色值的案例

在1.2節(jié)中對減少圖像色值有了一個簡單的介紹,但imread的flags色值的使用是有些的瞻佛,并不能任意的色值縮小為原來的1/3脱篙,1/5等,所以在本例中會實現(xiàn)將圖片的色值縮小為任意倍數(shù)伤柄。通過本例可以對像素的通道绊困,有更深刻的認(rèn)識。

int main() {

//【1】初始化Mat對象 Mat srcImage = imread("../1.jpg");

????imshow("【原始圖片】", srcImage);

????// 【2】按原始圖的參數(shù)規(guī)格來創(chuàng)建效果圖

????Mat dstImage(srcImage.cols, srcImage.rows, srcImage.type());

????// 參數(shù)1 傳入Mat對象适刀,參數(shù)2輸出的Mat對象秤朗,參數(shù)3將色值衰減為原來的1/32 ???

?????colorReduceDymatic(srcImage, dstImage, 32);

????// void imshow(const string& winname, InputArray image) winname要顯示的窗口名,image需要顯示的內(nèi)容

????imshow("【效果圖】", dstImage);

????// 按esc關(guān)閉窗口

????waitKey(0);

????}

????// 獲取到所有的像素點笔喉,因為該圖片是三通道的圖片取视,所以對每個像素的3個通道都需要進行像素值的衰減。通過這個方法將圖片的色值衰減為原來的1/32

????void colorReduceDymatic(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(i, j)[0] = outputImage.at(i, j)[0]/div*div ; //藍(lán)色通道

????????????????outputImage.at(i, j)[1] = outputImage.at(i, j)[1]/div*div ; //綠色通道

? ? ? ? ? ? ? ? outputImage.at(i, j)[2] = outputImage.at(i, j)[2]/div*div ; //紅色通道

????????}

????}

}

原始圖片

色值衰減之后的圖片

2.2 使用OpenCV進行簡單的繪制操作

在POCT-IR中涉及到需要畫線常挚,以提取T線和C線的色值的內(nèi)容作谭。所以在本節(jié)中將介紹一個通過OpenCV在Mat上繪制圖像的例子。

OpenCV繪制圖像的過程與iOS中繪制圖像的過程也是一致的奄毡,調(diào)用了基本的line和 ellipse函數(shù)進行繪制折欠。

#define WINDOW_WIDTH 600

void drawEllipse(Mat img, double angle);

// 畫線 Point 基本的數(shù)據(jù)結(jié)構(gòu) 定義線的起點和終點

void drawLine(Mat img, Point state, Point end);

int main() {

? ? Mat ellipse = Mat::zeros(Size(WINDOW_WIDTH, WINDOW_WIDTH), CV_8UC3);

? ? Mat line = Mat::zeros(Size(WINDOW_WIDTH, WINDOW_WIDTH), CV_8UC3);

? ? drawEllipse(ellipse, 90);

? ? imshow("【橢圓】", ellipse);


? ? drawLine(line, Point(0, 0), Point(100, 200));

? ? drawLine(line, Point(100, 200), Point(300, 200));

? ? drawLine(line, Point(300, 200), Point(300, 0));

? ? drawLine(line, Point(300, 0), Point(0, 0));

? ? imshow("【畫線】", line);

? ? waitKey();

? ? return 0;

}

// 使用line函數(shù)進行繪制

void drawLine(Mat img, Point start, Point end) {

? ? int thickness = 2;

? ? int lineType = 8;

? ? line(img,

? ? ? ? start,

? ? ? ? end,

? ? ? ? // 色值

? ? ? ? Scalar(0, 255, 255),

? ? ? ? thickness,

? ? ? ? lineType);

}

// 實現(xiàn)繪制不同角度、相同尺寸的橢圓

void drawEllipse(Mat img, double angle) {

? ? int thickness = 2;

? ? int lineType = 8;

? ? ellipse(img,

? ? ? ? ? ? Point(WINDOW_WIDTH/2, WINDOW_WIDTH/2),

? ? ? ? ? ? Size(WINDOW_WIDTH/4, WINDOW_WIDTH/16),

? ? ? ? ? ? angle,

? ? ? ? ? ? 0,

? ? ? ? ? ? 360,

? ? ? ? ? ? Scalar(255, 129, 9),

? ? ? ? ? ? thickness,

? ? ? ? ? ? lineType

? ? );

}

在本篇文章中介紹的API只涵蓋了OpenCV3 API極小的一部分內(nèi)容吼过,通過對本節(jié)開始內(nèi)容的學(xué)習(xí)锐秦,可以對OpenCV3的使用模式有初步了解,更多相關(guān)的接口使用事例.(因案例內(nèi)容都是手寫盗忱,如若遇到注釋解釋不清酱床,內(nèi)容描述有誤的部分請及時指正,以便進行及時修改趟佃。)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斤葱,一起剝皮案震驚了整個濱河市慷垮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揍堕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汤纸,死亡現(xiàn)場離奇詭異衩茸,居然都是意外死亡,警方通過查閱死者的電腦和手機贮泞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門楞慈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啃擦,你說我怎么就攤上這事囊蓝。” “怎么了令蛉?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵聚霜,是天一觀的道長。 經(jīng)常有香客問我珠叔,道長蝎宇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任祷安,我火速辦了婚禮姥芥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘汇鞭。我一直安慰自己凉唐,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布霍骄。 她就那樣靜靜地躺著台囱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腕巡。 梳的紋絲不亂的頭發(fā)上玄坦,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機與錄音绘沉,去河邊找鬼煎楣。 笑死,一個胖子當(dāng)著我的面吹牛车伞,可吹牛的內(nèi)容都是我干的择懂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼另玖,長吁一口氣:“原來是場噩夢啊……” “哼困曙!你這毒婦竟也來了表伦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤慷丽,失蹤者是張志新(化名)和其女友劉穎蹦哼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體要糊,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡纲熏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了锄俄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片局劲。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奶赠,靈堂內(nèi)的尸體忽然破棺而出鱼填,到底是詐尸還是另有隱情,我是刑警寧澤毅戈,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布苹丸,位于F島的核電站,受9級特大地震影響竹祷,放射性物質(zhì)發(fā)生泄漏谈跛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一塑陵、第九天 我趴在偏房一處隱蔽的房頂上張望感憾。 院中可真熱鬧,春花似錦令花、人聲如沸阻桅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嫂沉。三九已至,卻和暖如春扮碧,著一層夾襖步出監(jiān)牢的瞬間趟章,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工慎王, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蚓土,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓赖淤,卻偏偏與公主長得像蜀漆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子咱旱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容