Learning OpenCV with iOS:掩膜操作

一朱巨、前言

上一篇我們簡單講解了OpenCV的概念和基礎架構(gòu)之拨。本篇主要向大家介紹下圖像處理中一個比較重要的概念 -- 掩膜操作捅位。開始前我們先看下利用矩陣掩膜操作來加強圖像對比度的效果骤肛。

增強對比度

二诱咏、開胃菜-Mat對象

Mat

我們用眼睛看到的是圖像昌粤,而計算機卻不認識既绕。于是,人們使用數(shù)值的形式來記錄圖像涮坐,比如用RGB值記錄圖像的每個點凄贩,以此來表示圖像。就如上圖袱讹,我們看到的是一輛車疲扎,而計算機“看到”的是一個包含圖像值的矩陣。OpenCV的Mat對象對應的就是矩陣。Mat提供了許多便捷的API來創(chuàng)建椒丧、操作矩陣壹甥。

Mat基礎操作

Mat image = Mat(240, 320, CV_8UC3);

第一個參數(shù)是rows,該矩陣的行數(shù)瓜挽;第二個參數(shù)是cols盹廷,該矩陣的列數(shù);第三個參數(shù)是該矩陣元素的類型久橙。這句話表示創(chuàng)建一個大小為240×320的矩陣俄占,里面的元素為8位unsigned型,通道數(shù)(channel)有3個淆衷。

image.create(480, 640, CV_8UC3);

分配(或重新分配)image矩陣缸榄,把大小設為480×640,類型設為CV8UC3祝拯。

Mat image = Mat(3, 3, CV_32F, Scalar(5));

定義并初始化一個3×3的32bit浮點數(shù)矩陣甚带,每個元素都設為5。

uchar* ptr = image.ptr(row);

指針操作佳头,表示拿到image第row行的指針

uchar* output = image.ptr(row);
output[1] = value;

利用指針修改圖像鹰贵,表示修改image第row行的第2個數(shù)據(jù)為value。

Mat常用成員介紹

1康嘉、data
Mat對象中的一個指針碉输,指向存放矩陣數(shù)據(jù)的內(nèi)存(uchar* data)

2、dims
矩陣的維度亭珍,34的矩陣維度為2維敷钾,34*5的矩陣維度為3維

3、channels
矩陣通道肄梨,矩陣中的每一個矩陣元素擁有的值的個數(shù)阻荒,比如說 3 * 4 矩陣中一共 12 個元素,如果每個元素有三個值众羡,那么就說這個矩陣是 3 通道的侨赡,即 channels = 3。常見的是一張彩色圖片有紅粱侣、綠羊壹、藍三個通道。

4甜害、rows
矩陣的行數(shù)

5舶掖、cols
矩陣的列數(shù)

Mat與IplImage

OpenCV1使用基于C接口定義的圖像存儲格式IplImage存儲圖像。IplImage直接暴露內(nèi)存尔店,如果忘記釋放內(nèi)存眨攘,就會造成內(nèi)存泄漏主慰。

從OpenCV2開始,開始使用Mat類存儲圖像鲫售,具有以下優(yōu)勢:

  • 圖像的內(nèi)存分配和釋放由Mat類自動管理

  • Mat類由兩部分數(shù)據(jù)組成:矩陣頭(包含矩陣尺寸共螺、存儲方法、存儲地址等)和一個指向存儲所有像素值的矩陣(根據(jù)所選存儲方法的不同情竹,矩陣可以是不同的維數(shù))的指針藐不。Mat在進行賦值和拷貝時,只復制矩陣頭秦效,而不復制矩陣雏蛮,提高效率。如果矩陣屬于多個Mat對象阱州,則通過引用計數(shù)來判斷挑秉,當最后一個使用它的對象,則負責釋放矩陣苔货。

  • 可以使用clone和copyTo函數(shù)犀概,不僅復制矩陣頭還復制矩陣。

三夜惭、掩膜操作

數(shù)字圖像處理中的掩膜的概念是借鑒于PCB制版的過程姻灶,在半導體制造中,許多芯片工藝步驟采用光刻技術诈茧,用于這些步驟的圖形“底片”稱為掩膜(也稱作“掩牟恚”),其作用是:在硅片上選定的區(qū)域中對一個不透明的圖形模板遮蓋若皱,繼而下面的腐蝕或擴散將只影響選定的區(qū)域以外的區(qū)域镊叁。
圖像掩膜與其類似尘颓,用選定的圖像走触、圖形或物體,對處理的圖像(全部或局部)進行遮擋疤苹,來控制圖像處理的區(qū)域或處理過程互广。
光學圖像處理中,掩模可以是膠片卧土、濾光片等惫皱。數(shù)字圖像處理中,掩模為二維矩陣數(shù)組,有時也用多值圖像。

是不是概念看得一頭霧水尤莺,沒事的旅敷,我第一次看概念的也是一樣樣的。下面我以例子來輔助大家了解掩膜颤霎。

摳下鎧的頭

接下來我們以代碼角度分析下究竟什么是掩膜媳谁。

    // image為鎧的圖片
    Mat src;
    UIImageToMat(image, src);
    
    Mat mask = Mat::zeros(src.size(), CV_8UC1);
    Rect2i r = Rect2i(120, 80, 100, 100);
    mask(r).setTo(255);
    
    Mat dst;
    src.copyTo(dst, mask);

第一步建立與原圖一樣大小的mask圖像涂滴,并將所有像素初始化為0,因此全圖成了一張全黑色圖晴音。
第二步將mask圖中的r區(qū)域的所有像素值設置為255,也就是整個r區(qū)域變成了白色柔纵。

 Mat mask = Mat::zeros(src.size(), CV_8UC1);
 mask(r).setTo(255);
mask圖片

使用mask將原始圖src拷貝到目的圖dst上。

src.copyTo(dst, mask);

這個拷貝的動作完整版本是這樣的:

原圖(src)與掩膜(mask)進行與運算后得到了結(jié)果圖(dst)锤躁。

其實就是原圖中的每個像素和掩膜中的每個對應像素進行與運算搁料。比如1 & 1 = 1;1 & 0 = 0系羞;

比如一個3 * 3的圖像與3 * 3的掩膜進行運算郭计,得到的結(jié)果圖像就是:

mask.png

所以,mask就是位圖椒振,來過濾像素拣宏。如果mask像素的值是非0的,我就保留杠人,否則就丟棄勋乾。

因為我們上面得到的mask中,感興趣的區(qū)域是白色的嗡善,表明感興趣區(qū)域的像素都是非0辑莫,而非感興趣區(qū)域都是黑色,表明那些區(qū)域的像素都是0罩引。一旦原圖與mask圖進行與運算后各吨,得到的結(jié)果圖只留下原始圖感興趣區(qū)域的圖像了。也正剩下鎧的頭部了袁铐。

增強對比度

矩陣的掩膜操作就是根據(jù)掩膜來重新計算每個像素的像素值揭蜒,掩膜(mask)也被稱為kernel。
通過掩膜操作實現(xiàn)圖像對比度提高的公式如下剔桨。

I(i,j) = 5*I(i,j) - [I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]

注:這里看不懂不要緊屉更,先看具體的實現(xiàn),回頭我們再一起回顧這里洒缀。

上面的公式瑰谜,轉(zhuǎn)換成矩陣就如下圖所示

kernel

紅色是中心像素,從上到下树绩,從左到右對每個像素做同樣的處理操作萨脑,具體過程如下圖,深灰色底表示原圖像饺饭,每次移動kernel便根據(jù)公司計算新值并更新矩陣渤早。最終得到的結(jié)果就是對比度提高之后的輸出圖像。

kernel

具體的代碼如下:

    // image為鎧的圖片
    Mat src;
    UIImageToMat(image, src);
    
    int cols = (src.cols-1) * src.channels();
    int offset = src.channels();
    int rows = src.rows;
    
    Mat dst = Mat(src.size(), src.type());
    for (int row = 1; row < rows-1; row++) {
        uchar* previous = src.ptr(row-1);
        uchar* current = src.ptr(row);
        uchar* next = src.ptr(row+1);
        uchar* output = dst.ptr(row);
        for (int col = offset; col < cols; col++) {
            output[col] = saturate_cast<uchar>(5*current[col] - (current[col-offset] + current[col +offset] + previous[col] + next[col]));
        }
    }

/*
注:
saturate_cast<uchar>(-100)瘫俊,返回0
saturate_cast<uchar>(288)鹊杖,返回255
saturate_cast<uchar>(100)提鸟,返回100
這個函數(shù)的功能是確保RGB值范圍在0~255之間。
*/

效果


增強對比度

接下來我們來回顧下上面的那個公式

I(i,j) = 5*I(i,j) - [I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]

其實這個公式就是5倍的中心像素減去周邊的四個像素之和仅淑。
我們舉兩個例子來看下這個公式的結(jié)果称勋。

demo1
demo2

我們可以大致看到若是中心點的值大于周圍,則計算后的結(jié)果會將中心點與周圍的值差距拉得更大涯竟;
若是中心點的值小于周圍赡鲜,則計算后的結(jié)果也會將中心點與周圍的值差距拉大。這樣“大的大庐船,小的小”結(jié)果不就是對比明顯了嗎银酬,也就是提高了對比度。

大家會發(fā)現(xiàn)這樣做掩膜操作也太麻煩了筐钟。這個時候我們就找OpenCV來幫個忙揩瞪,看看它是怎么實現(xiàn)的。

    Mat src;
    UIImageToMat(image, src);
    
    Mat dst;
    Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    filter2D(src, dst, src.depth(), kernel);

一個filter2D搞定篓冲!定義如下:

void filter2D( InputArray src, OutputArray dst, int ddepth,
                            InputArray kernel, Point anchor=Point(-1,-1),
                            double delta=0, int borderType=BORDER_DEFAULT );

其中src與dst是Mat類型變量李破、depth表示位圖深度,有32壹将、24嗤攻、8等。

四诽俯、小結(jié)

本篇主要介紹了Mat對象的基本用法妇菱,并通過兩個例子講解了掩膜操作的原理和實現(xiàn)。下一篇還是會以這樣的形式講解OpenCV的其他知識暴区,有更好建議的朋友可以給我留言闯团,see you later!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市仙粱,隨后出現(xiàn)的幾起案子房交,更是在濱河造成了極大的恐慌,老刑警劉巖缰盏,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涌萤,死亡現(xiàn)場離奇詭異淹遵,居然都是意外死亡口猜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門透揣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來济炎,“玉大人,你說我怎么就攤上這事辐真⌒肷校” “怎么了崖堤?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耐床。 經(jīng)常有香客問我密幔,道長,這世上最難降的妖魔是什么撩轰? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任胯甩,我火速辦了婚禮,結(jié)果婚禮上堪嫂,老公的妹妹穿的比我還像新娘偎箫。我一直安慰自己,他們只是感情好皆串,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布淹办。 她就那樣靜靜地躺著,像睡著了一般恶复。 火紅的嫁衣襯著肌膚如雪怜森。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天谤牡,我揣著相機與錄音塔插,去河邊找鬼。 笑死拓哟,一個胖子當著我的面吹牛想许,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播断序,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼流纹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了违诗?” 一聲冷哼從身側(cè)響起漱凝,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诸迟,沒想到半個月后茸炒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡阵苇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年壁公,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绅项。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡紊册,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出快耿,到底是詐尸還是另有隱情囊陡,我是刑警寧澤芳绩,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站撞反,受9級特大地震影響妥色,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜遏片,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一垛膝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丁稀,春花似錦吼拥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至授账,卻和暖如春枯跑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背白热。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工敛助, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屋确。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓纳击,卻偏偏與公主長得像,于是被迫代替她去往敵國和親攻臀。 傳聞我的和親對象是個殘疾皇子焕数,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

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