第 5 章 用形態(tài)學(xué)運(yùn)算變換圖像


本章包括以下內(nèi)容:

  • 用形態(tài)學(xué)濾波器腐蝕和膨脹圖像;
  • 用形態(tài)學(xué)濾波器開啟和閉合圖像;
  • 在灰度圖像中應(yīng)用形態(tài)學(xué)運(yùn)算戏羽;
  • 用分水嶺算法實(shí)現(xiàn)圖像分割;
  • 用MSER 算法提取特征區(qū)域楼吃。


5.2 用形態(tài)學(xué)濾波器腐蝕和膨脹圖像

形態(tài)學(xué)濾波器通常作用于二值圖像始花。我們習(xí)慣用高像素值(白色)表示前景物體,用低像素值(黑色)表示背景物體孩锡。

在形態(tài)學(xué)術(shù)語中酷宵,下面的圖像稱為第4 章所建圖像的補(bǔ)碼。

result.jpg

OpenCV 用簡單的函數(shù)實(shí)現(xiàn)了腐蝕和膨脹運(yùn)算躬窜,它們分別是cv:erode 和cv:dilate浇垦,用法也很簡單:

// 讀取輸入圖像
cv::Mat image= cv::imread("binary.bmp");
// 腐蝕圖像
// 采用默認(rèn)的3×3 結(jié)構(gòu)元素
cv::Mat eroded; // 目標(biāo)圖像
cv::erode(image,eroded,cv::Mat());

// 膨脹圖像
cv::Mat dilated; // 目標(biāo)圖像
cv::dilate(image,dilated,cv::Mat());

這些函數(shù)生成的兩幅圖像如下所示。

result.jpg
result.jpg

腐蝕就是把當(dāng)前像素替換成所定義像素集合中的最小像素值;
膨脹是腐蝕的反運(yùn)算,它把當(dāng)前像素替換成所定義像素集合中的最大像素值颠蕴。

腐蝕時(shí),如果結(jié)構(gòu)元素放到某個(gè)像素位置時(shí)碰到了背景(即交集中有一個(gè)像素是黑色的),那么這個(gè)像素就
變?yōu)楸尘叭耘慌蛎洉r(shí)厕倍,如果結(jié)構(gòu)元素放到某個(gè)背景像素位置時(shí)碰到了前景物體,那么這個(gè)像素就被標(biāo)為白色贩疙。

正因如此讹弯,圖像腐蝕后物體尺寸會縮锌黾取(形狀被腐蝕),而圖像膨脹后物體會擴(kuò)大组民。

在腐蝕圖像中棒仍,有些面積較小的物體(可看作背景中的“噪聲”像素)會徹底消失。與之類似臭胜,膨脹后的物體會變大莫其,而物體中一些“空隙”會被填滿。

OpenCV 默認(rèn)使用3×3 正方形結(jié)構(gòu)元素耸三。在調(diào)用函數(shù)時(shí)乱陡,參考前面的例子將第三個(gè)參數(shù)指定為空矩陣(即cv::Mat()),就能得到默認(rèn)的結(jié)構(gòu)元素仪壮。你也可以通過提供一個(gè)矩陣來指定結(jié)構(gòu)元素的大泻┑摺(以及形狀),矩陣中的非零元素將構(gòu)成結(jié)構(gòu)元素积锅。下面的例子使用7×7 的結(jié)構(gòu)元素:

// 用更大的結(jié)構(gòu)元素腐蝕圖像
// 創(chuàng)建7×7 的mat 變量爽彤,其中全部元素都為1
cv::Mat element(7,7,CV_8U,cv::Scalar(1));
// 用這個(gè)結(jié)構(gòu)元素腐蝕圖像
cv::erode(image,eroded,element);

這次的結(jié)果更有破壞性,如下圖所示缚陷。

result.jpg

還有一種方法也能得到類似的結(jié)果适篙,就是在圖像上反復(fù)應(yīng)用同一個(gè)結(jié)構(gòu)元素。這兩個(gè)函數(shù)都有一個(gè)用于指定重復(fù)次數(shù)的可選參數(shù):

// 腐蝕圖像三次
cv::erode(image,eroded,cv::Mat(),cv::Point(-1,-1),3);

參數(shù)cv::Point(-1,-1)表示原點(diǎn)是矩陣的中心點(diǎn)(默認(rèn)值)蹬跃,也可以定義在結(jié)構(gòu)元素上的其他位置匙瘪。由此得到的圖像與使用7×7 結(jié)構(gòu)元素得到的圖像是一樣的。實(shí)際上蝶缀,對圖像腐蝕兩次相當(dāng)于對結(jié)構(gòu)元素自身膨脹后的圖像進(jìn)行腐蝕丹喻。這個(gè)規(guī)則也適用于膨脹。

最后翁都,鑒于前景/背景概念有很大的隨意性碍论,我們可得到以下的實(shí)驗(yàn)結(jié)論(這是腐蝕/膨脹運(yùn)算的基本性質(zhì))。用結(jié)構(gòu)元素腐蝕前景物體可看作對圖像背景部分的膨脹柄慰,也就是說:

  • 腐蝕圖像相當(dāng)于對其反色圖像膨脹后再取反色鳍悠;
  • 膨脹圖像相當(dāng)于對其反色圖像腐蝕后再取反色。

另外坐搔,OpenCV 的形態(tài)學(xué)函數(shù)支持就地處理藏研。這意味著輸入圖像和輸出圖像可以采用同一個(gè)變量。

cv::erode(image,image,cv::Mat());


5.3 用形態(tài)學(xué)濾波器開啟和閉合圖像

本節(jié)將講解開啟和閉合運(yùn)算概行。

應(yīng)用較高級別的形態(tài)學(xué)濾波器蠢挡,需要用cv::morphologyEx 函數(shù),例如下面的調(diào)用方法將適用于閉合運(yùn)算:

    // 閉合圖像
    cv::Mat element5(5, 5, CV_8U, cv::Scalar(1));
    cv::Mat closed;
    cv::morphologyEx(image, closed, // 輸入和輸出的圖像
        cv::MORPH_CLOSE, // 運(yùn)算符
        element5); // 結(jié)構(gòu)元素

注意,為了讓濾波器的效果更加明顯业踏,這里使用了5×5 的結(jié)構(gòu)元素禽炬。如果輸入上節(jié)的二值圖像,將得到如下所示的圖像勤家。

result.jpg

與之類似腹尖,應(yīng)用形態(tài)學(xué)開啟運(yùn)算后將得到如下圖像。

cv::Mat opened;
cv::morphologyEx(image, opened, cv::MORPH_OPEN, element5);
result.jpg

開啟和閉合濾波器的定義只與基本的腐蝕和膨脹運(yùn)算有關(guān):閉合的定義是對圖像先膨脹后腐蝕伐脖,開啟的定義是對圖像先腐蝕后膨脹热幔。

因此可以用以下方法對圖像做閉合運(yùn)算:

// 膨脹原圖像
cv::dilate(image, result, cv::Mat());
// 就地腐蝕膨脹后的圖像
cv::erode(result, result, cv::Mat());

調(diào)換這兩個(gè)函數(shù)的調(diào)用次序,就能得到開啟濾波器晓殊。

查看閉合濾波器的結(jié)果断凶,可看到白色的前景物體中的小空隙已經(jīng)被填滿。閉合濾波器也會把鄰近的物體連接起來巫俺∪纤福基本上,所有小到不能容納完整結(jié)構(gòu)元素的空隙或間隙都會被閉合濾波器消除介汹。

與閉合濾波器相反却嗡,開啟濾波器消除了背景中的幾個(gè)小物體。所有小到不能容納完整結(jié)構(gòu)元素的物體都會被移除嘹承。

這些濾波器常用于目標(biāo)檢測窗价。閉合濾波器可把錯(cuò)誤分裂成小碎片的物體連接起來,而開啟濾波器可以移除因圖像噪聲產(chǎn)生的斑點(diǎn)叹卷。因此最好按一定的順序調(diào)用這些濾波器撼港。如果優(yōu)先考慮過濾噪聲,可以先開啟后閉合骤竹,但這樣做的壞處是會消除掉部分物體碎片帝牡。

先使用開啟濾波器,再使用閉合濾波器蒙揣,會得到如下結(jié)果靶溜。

result.jpg

注意,對一幅圖像進(jìn)行多次同樣的開啟運(yùn)算是沒有作用的(閉合運(yùn)算也一樣)懒震。事實(shí)上罩息,因?yàn)榈谝淮问褂瞄_啟濾波器時(shí)已經(jīng)填充了空隙,再使用同一個(gè)濾波器將不會使圖像產(chǎn)生變化个扰。


5.4 在灰度圖像中應(yīng)用形態(tài)學(xué)運(yùn)算

本節(jié)將介紹兩種形態(tài)學(xué)運(yùn)算瓷炮,將它們應(yīng)用于灰度圖像上可以檢測圖像的特征。

形態(tài)學(xué)梯度運(yùn)算可以提取出圖像的邊緣递宅,具體方法為使用cv::morphologyEx 函數(shù)娘香,代碼如下所示:

    // 用3×3 結(jié)構(gòu)元素得到梯度圖像
    cv::Mat result;
    cv::morphologyEx(image, result,
        cv::MORPH_GRADIENT, cv::Mat());

得到圖像中物體的輪廓(為方便觀察冬筒,對圖像做了反色處理)。

result.jpg

另一種很實(shí)用的形態(tài)學(xué)運(yùn)算是頂帽(hat-top)變換茅主,它可以從圖像中提取出局部的小型前景物體。為了說明該運(yùn)算的效果土榴,我們用本書中一頁的照片做試驗(yàn)诀姚。由圖可知,頁面的光照并不均勻玷禽。通過使用cv::morphologyEx 函數(shù)并采用正確的參數(shù)赫段,可以調(diào)用黑帽變換提取出頁面上的文字(作為前景物體):

    // 使用7×7 結(jié)構(gòu)元素做黑帽變換
    cv::Mat element7(7, 7, CV_8U, cv::Scalar(1));
    cv::morphologyEx(image, result, cv::MORPH_BLACKHAT, element7);

運(yùn)行結(jié)果如下圖所示(反色處理),它可以從圖像中提取出大部分文字矢赁。

result.jpg

理解形態(tài)學(xué)運(yùn)算在灰度圖像上的效果有一個(gè)好辦法糯笙,就是把圖像看作是一個(gè)拓?fù)涞孛玻煌幕叶燃墑e代表不同的高度(或海拔)撩银「椋基于這種觀點(diǎn),明亮的區(qū)域代表高山额获,黑暗的區(qū)域代表深谷够庙;邊緣相當(dāng)于黑暗和明亮像素之間的快速過渡,因此可以比作陡峭的懸崖抄邀。

腐蝕這種地形的最終結(jié)果是:每個(gè)像素被替換成特定鄰域內(nèi)的最小值耘眨,從而降低它的高度。結(jié)果是懸崖“縮小”境肾,山谷“擴(kuò)大”剔难。膨脹的效果剛好相反,即懸崖“擴(kuò)大”奥喻,山谷“縮小”偶宫。但不管哪種情況,平地(即強(qiáng)度值固定的區(qū)域)都會相對保持不變衫嵌。

根據(jù)這個(gè)結(jié)論读宙,可以得到一種檢測圖像邊緣(或懸崖)的簡單方法,即通過計(jì)算膨脹后的圖像與腐蝕后的圖像之間的的差距得到邊緣楔绞。因?yàn)檫@兩種轉(zhuǎn)換后圖像的差別主要在邊緣地帶结闸,所以相減后會突出邊緣。

在cv::morphologyEx 函數(shù)中輸入cv::MORPH_GRADIENT 參數(shù)酒朵,即可實(shí)現(xiàn)此功能桦锄。顯然,結(jié)構(gòu)元素越大蔫耽,檢測到的邊緣就越寬结耀。這種邊緣檢測運(yùn)算稱為Beucher 梯度留夜。

注意還有兩種簡單的方法能得到類似結(jié)果,即用膨脹后的圖像減去原始圖像图甜,或者用原始圖像減去腐蝕后的圖像碍粥,那樣得到的邊緣會更窄。

頂帽運(yùn)算也基于圖像比對黑毅,它使用了開啟和閉合運(yùn)算嚼摩。因?yàn)榛叶葓D像進(jìn)行形態(tài)學(xué)開啟運(yùn)算時(shí)會先對圖像進(jìn)行腐蝕,局部的尖銳部分會被消除矿瘦,其他部分則將保留下來枕面。因此,原始圖像和經(jīng)過開啟運(yùn)算的圖像的比對結(jié)果就是局部的尖銳部分缚去。這些尖銳部分就是我們需要提取的前景物體潮秘。

對于本書的照片來說,前景物體就是頁面上的文字易结。因?yàn)闀緸榘椎缀谧终碥瘢晕覀儾捎盟幕パa(bǔ)運(yùn)算,即黑帽算法衬衬。它將對圖像做閉合運(yùn)算买猖,然后從得到的結(jié)果中減去原始圖像。這里采用7×7 的結(jié)構(gòu)元素滋尉,它足夠大了玉控,能確保移除文字。


5.5 用分水嶺算法實(shí)現(xiàn)圖像分割

分水嶺變換是一種流行的圖像處理算法狮惜,用于快速將圖像分割成多個(gè)同質(zhì)區(qū)域高诺。

它基于這樣的思想:如果把圖像看作一個(gè)拓?fù)涞孛玻敲赐悈^(qū)域就相當(dāng)于陡峭邊緣內(nèi)相對平坦的盆地碾篡。分
水嶺算法通過逐步增高水位虱而,把地貌分割成多個(gè)部分。OpenCV 提出了該算法的改進(jìn)版本开泽,使用一系列預(yù)定義標(biāo)記來引導(dǎo)圖像分割的定義方式牡拇。

使用分水嶺分割法需要調(diào)用cv::watershed 函數(shù)。該函數(shù)的輸入對象是一個(gè)標(biāo)記圖像穆律,圖像的像素值為32 位有符號整數(shù)惠呼,每個(gè)非零像素代表一個(gè)標(biāo)簽。它的原理是對圖像中部分像素做標(biāo)記峦耘,表明它們的所屬區(qū)域是已知的剔蹋。分水嶺算法可根據(jù)這個(gè)初始標(biāo)簽確定其他像素所屬的區(qū)域。

本節(jié)將先建立一個(gè)標(biāo)記圖像作為灰度圖像辅髓,然后將其轉(zhuǎn)換成整型圖像泣崩。我們把這個(gè)步驟封裝進(jìn)WatershedSegmenter 類少梁,它包括指定標(biāo)記圖像和計(jì)算分水嶺的方法:

class WatershedSegmenter {
private:
    cv::Mat markers;
public:
    void setMarkers(const cv::Mat& markerImage) {
        // 轉(zhuǎn)換成整數(shù)型圖像
        markerImage.convertTo(markers, CV_32S);
    }
    cv::Mat process(const cv::Mat& image) {
        // 應(yīng)用分水嶺
        cv::watershed(image, markers);
        return markers;
    }

不同應(yīng)用程序獲得標(biāo)記的方式各不相同。例如矫付,可在預(yù)處理過程中識別出一些屬于某個(gè)感興趣物體的像素凯沪。然后,根據(jù)初始檢測結(jié)果买优,使用分水嶺算法劃出整個(gè)物體的邊緣著洼。

binary.jpg

本節(jié)將利用本章一直使用的二值圖像,識別出對應(yīng)原始圖像中的動物而叼。因此,我們需要從二值圖像中識別出屬于前景(動物)的像素以及屬于背景(主要是草地)的像素豹悬。這里把前景像素標(biāo)記為255葵陵,把背景像素標(biāo)記為128(該數(shù)字是隨意選擇的,任何不等于255 的數(shù)字都可以)瞻佛。其他像素的標(biāo)簽是未知的脱篙,標(biāo)記為0。

現(xiàn)在伤柄,這個(gè)二值圖像包含了屬于圖像不同部分的白色像素绊困,因此要對圖像做深度腐蝕運(yùn)算,只保留明顯屬于前景物體的像素:

    // 消除噪聲和細(xì)小物體
    cv::Mat fg;
    cv::erode(image, fg, cv::Mat(), cv::Point(-1, -1), 4);

得到的圖像如下所示适刀。

result.jpg

注意秤朗,仍然有少量屬于背景(森林)的像素保留了下來,不用管它們笔喉,可將它們看作感興趣物體取视。與之類似,我們可以通過對原二值圖像做一次大幅度的膨脹運(yùn)算來選中一些背景像素:

// 標(biāo)識不含物體的圖像像素
cv::Mat bg;
cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),4);
cv::threshold(bg,bg,1,128,cv::THRESH_BINARY_INV);

得到的黑色像素對應(yīng)背景像素常挚。因此在膨脹后作谭,要立即通過閾值化運(yùn)算把它們賦值為128。得到的圖像如下所示奄毡。

result.jpg

合并這兩幅圖像折欠,得到標(biāo)記圖像,代碼為:

// 創(chuàng)建標(biāo)記圖像
cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0));
markers= fg+bg;

下面的圖像將被輸入分水嶺算法吼过。

result.jpg

毫無疑問锐秦,在這個(gè)輸入圖像中,白色區(qū)域?qū)儆谇熬拔矬w那先,灰色區(qū)域?qū)儆诒尘芭┾谏珔^(qū)域帶有未知標(biāo)簽。分水嶺算法的作用就是明確地劃分前景和背景售淡,并對黑色區(qū)域的像素做出標(biāo)記(屬于前景還是背景)斤葱】犊澹可用下面的方法來分割圖像:

// 創(chuàng)建分水嶺分割類的對象
WatershedSegmenter segmenter;
// 設(shè)置標(biāo)記圖像,然后執(zhí)行分割過程
segmenter.setMarkers(markers);
segmenter.process(image);

上面的代碼會修改標(biāo)記圖像揍堕,每個(gè)值為0 的像素都會被賦予一個(gè)輸入標(biāo)簽料身,而邊緣處的像素被賦值為-1,得到的標(biāo)簽圖像如圖所示衩茸。

result.jpg

邊緣圖像如圖所示芹血。

result.jpg

跟前面幾節(jié)一樣,我們在描述分水嶺算法時(shí)用拓?fù)涞貓D來做類比楞慈。用分水嶺算法分割圖像的原理是從高度0 開始逐步用洪水淹沒圖像幔烛。當(dāng)“水”的高度逐步增加時(shí)(到1、2囊蓝、3 等)饿悬,會形成聚水的盆地。隨著盆地面積逐步變大聚霜,兩個(gè)盆地的水最終會匯合到一起狡恬。這時(shí)就要?jiǎng)?chuàng)建一個(gè)分水嶺,用來分割這兩個(gè)盆地蝎宇。當(dāng)水位達(dá)到最大高度時(shí)弟劲,創(chuàng)建的盆地和分水嶺就組成了分水嶺分割圖。

可以想象姥芥,在水淹過程的開始階段會創(chuàng)建很多細(xì)小的獨(dú)立盆地兔乞。當(dāng)所有盆地匯合時(shí),就會創(chuàng)建很多分水嶺線條凉唐,導(dǎo)致圖像被過度分割报嵌。要解決這個(gè)問題,就要對這個(gè)算法進(jìn)行修改熊榛,使水淹過程從一組預(yù)先定義好的標(biāo)記像素開始锚国。每個(gè)用標(biāo)記創(chuàng)建的盆地,都按照初始標(biāo)記的值加上標(biāo)簽玄坦。如果兩個(gè)標(biāo)簽相同的盆地匯合血筑,就不創(chuàng)建分水嶺,以避免過度分割煎楣。調(diào)用cv::watershed 函數(shù)時(shí)就執(zhí)行了這些過程豺总。輸入的標(biāo)記圖像會被修改,用以生成最終的分水嶺分割圖择懂。輸入的標(biāo)記圖像可以含有任意數(shù)值的標(biāo)簽喻喳,未知標(biāo)簽的像素值為0。標(biāo)記圖像的類型選用32 位有符號整數(shù)困曙,以便定義超過255 個(gè)的標(biāo)簽表伦。另外谦去,可以把分水嶺的對應(yīng)像素設(shè)為特殊值-1。

為了方便顯示結(jié)果蹦哼,我們采用兩種特殊方法鳄哭。第一種方法返回由標(biāo)簽組成的圖像(包含值為0 的分水嶺)。該方法通過閾值化很容易實(shí)現(xiàn)纲熏,代碼如下所示:

// 以圖像的形式返回結(jié)果
cv::Mat getSegmentation() {
    cv::Mat tmp;
    // 所有標(biāo)簽值大于255 的區(qū)段都賦值為255
    markers.convertTo(tmp, CV_8U);
    return tmp;
}

與之類似妆丘,第二種方法返回一幅圖像,圖像中分水嶺線條賦值為0局劲,其他部分賦值為255勺拣。這次用cv::convertTo 方法來獲得結(jié)果,代碼如下所示:

// 以圖像的形式返回分水嶺
cv::Mat getWatersheds() {
    cv::Mat tmp;
    // 在變換前鱼填,把每個(gè)像素p 轉(zhuǎn)換為255p+255
    markers.convertTo(tmp, CV_8U, 255, 255);
    return tmp;
}

在變換前對圖像做線性轉(zhuǎn)換宣脉,使值為-1 的像素變?yōu)?(因?yàn)?1*255+255=0)。

值大于255 的像素賦值為255剔氏。這是因?yàn)閷⒂蟹栒麛?shù)轉(zhuǎn)換成無符號字符型時(shí),應(yīng)用了飽和度運(yùn)算竹祷。


5.6 用MSER 算法提取特征區(qū)域

最大穩(wěn)定外部區(qū)域(MSER)算法也用相同的水淹類比谈跛,以便從圖像中提取有意義的區(qū)域。創(chuàng)建這些區(qū)域時(shí)也使用逐步提高水位的方法塑陵,但是這次我們關(guān)注的是在水淹過程中的某段時(shí)間內(nèi)感憾,保持相對穩(wěn)定的盆地×罨ǎ可以發(fā)現(xiàn)阻桅,這些區(qū)域?qū)?yīng)著圖像中某些物體的特殊部分。

計(jì)算圖像MSER 的基礎(chǔ)類是cv::MSER兼都。cv::MSER 類的實(shí)例可以通過create 方法創(chuàng)建嫂沉。我們在初始化時(shí)指定被檢測區(qū)域的最小和最大尺寸,以便限制被檢測特征的數(shù)量扮碧,調(diào)用方式如下:

    // 基本的MSER 檢測器
    cv::Ptr<cv::MSER> ptrMSER = cv::MSER::create(
            5, // 局部檢測時(shí)使用的增量值
            200, // 允許的最小面積
            2000); // 允許的最大面積

現(xiàn)在可以通過調(diào)用detectRegions 方法來獲得MSER趟章,指定輸入圖像和一個(gè)相關(guān)的輸出數(shù)據(jù)結(jié)構(gòu),代碼如下所示:

// 點(diǎn)集的容器
std::vector<std::vector<cv::Point> > points;
// 矩形的容器
std::vector<cv::Rect> rects;
// 檢測MSER 特征
ptrMSER->detectRegions(image, points, rects);

檢測結(jié)果放在兩個(gè)容器中慎王。第一個(gè)是區(qū)域的容器蚓土,每個(gè)區(qū)域用組成它的像素點(diǎn)表示;第二個(gè)是矩形的容器赖淤,每個(gè)矩形包圍一個(gè)區(qū)域蜀漆。為了呈現(xiàn)結(jié)果,創(chuàng)建一個(gè)空白圖像咱旱,在圖像上用不同的顏色顯示檢測到的區(qū)域(顏色是隨機(jī)選擇的)确丢。用以下代碼實(shí)現(xiàn):

    // 創(chuàng)建白色圖像
    cv::Mat output(image.size(), CV_8UC3);
    output = cv::Scalar(255, 255, 255);
    // OpenCV 隨機(jī)數(shù)生成器
    cv::RNG rng;
    // 針對每個(gè)檢測到的特征區(qū)域绷耍,在彩色區(qū)域顯示MSER
    // 反向排序,先顯示較大的MSER
    for (std::vector<std::vector<cv::Point> >::reverse_iterator
        it = points.rbegin();
        it != points.rend(); ++it) {
        // 生成隨機(jī)顏色
        cv::Vec3b c(rng.uniform(0, 254),
            rng.uniform(0, 254), rng.uniform(0, 254));
        // 針對MSER 集合中的每個(gè)點(diǎn)
        for (std::vector<cv::Point>::iterator itPts = it->begin();
            itPts != it->end(); ++itPts) {
            // 不重寫MSER 的像素
            if (output.at<cv::Vec3b>(*itPts)[0] == 255) {
                output.at<cv::Vec3b>(*itPts) = c;
            }
        }
    }

注意蠕嫁,MSER 會形成層疊區(qū)域锨天。為了顯示全部區(qū)域,如果一個(gè)較大區(qū)域內(nèi)包含了較小的區(qū)域剃毒,就不能覆蓋它病袄。可以從下圖中檢測出MSER赘阀。

building.jpg

結(jié)果如下圖所示益缠。

result.jpg

圖中沒有顯示全部區(qū)域,但是可以看出基公,通過這種方法能從圖片中提取到一些有意義的區(qū)域(例如建筑物的窗戶)幅慌。

MSER 的原理與分水嶺算法相同,即高度為0~255轰豆,逐漸淹沒圖像胰伍。隨著水位的升高,顏色較黑并且邊界陡峭的區(qū)域會形成盆地 酸休,并且在一段時(shí)間內(nèi)有相對穩(wěn)定的形狀(用水位表示顏色骂租,水位高低代表了像素值的強(qiáng)度)。這些穩(wěn)定的盆地就是MSER斑司。

檢測它們的方法是渗饮,觀察每個(gè)水位連通的區(qū)域(即盆地)并測量它們的穩(wěn)定性。測量穩(wěn)定性的方法是:計(jì)算區(qū)域的當(dāng)前面積以及該區(qū)域原先的面積(比當(dāng)前水位低一個(gè)特定值的時(shí)候)宿刮,并比較這兩個(gè)面積互站。如果相對變化達(dá)到局部最小值,就認(rèn)為這個(gè)區(qū)域是MSER僵缺。

增量值將作為cv::MSER 類構(gòu)造函數(shù)的第一個(gè)參數(shù)胡桃,用以測量相對穩(wěn)定性,默認(rèn)值為5磕潮。另外要注意标捺,區(qū)域面積必須在預(yù)定義的范圍內(nèi)。構(gòu)造函數(shù)中后面兩個(gè)參數(shù)就是允許的最小和最大區(qū)域尺寸揉抵。另外必須確保MSER 是穩(wěn)定的(第四個(gè)參數(shù))亡容,即形狀的相對變化必須足夠小。

MSER 檢測器首先輸出一個(gè)包含像素集的容器冤今,每個(gè)像素集構(gòu)成一個(gè)區(qū)域闺兢。因?yàn)槲覀冃枰页稣麄€(gè)區(qū)域的位置,而不是里面的單個(gè)像素,所以通常用包含了被檢測區(qū)域的幾何形狀表示一個(gè)MSER屋谭。

檢測過程中輸出的第二項(xiàng)是一系列矩形脚囊,畫出所有矩形就能表示檢測的結(jié)果。但是這樣會畫出許多矩形桐磁,使結(jié)果很不直觀(區(qū)域之間還會互相包含悔耘,結(jié)果更加混亂)。這個(gè)例子主要想檢測出大樓中的窗戶我擂,因此要提取出所有包含垂直矩形的區(qū)域衬以。實(shí)現(xiàn)方法是將每個(gè)矩形的面積與檢測到的對應(yīng)區(qū)域進(jìn)行比較,如果兩者一致(這里用的判斷標(biāo)準(zhǔn)是兩者比例超過0.6)校摩,那么它就是一個(gè)MSER看峻。測試代碼如下所示:

    // 提取并顯示矩形的MSER
    std::vector<cv::Rect>::iterator itr = rects.begin();
    std::vector<std::vector<cv::Point> >::iterator itp = points.begin();
    for (; itr != rects.end(); ++itr, ++itp) {
        // 檢查兩者比例
        if (static_cast<double>(itp->size()) / itr->area() > 0.6)
            cv::rectangle(image, *itr, cv::Scalar(255), 2);
    }

提取到的MSER 如下圖所示。

result.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衙吩,一起剝皮案震驚了整個(gè)濱河市互妓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坤塞,老刑警劉巖冯勉,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異摹芙,居然都是意外死亡灼狰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門瘫辩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坛悉,你說我怎么就攤上這事伐厌。” “怎么了裸影?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵挣轨,是天一觀的道長。 經(jīng)常有香客問我轩猩,道長卷扮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任均践,我火速辦了婚禮晤锹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘彤委。我一直安慰自己鞭铆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布焦影。 她就那樣靜靜地躺著车遂,像睡著了一般封断。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舶担,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天坡疼,我揣著相機(jī)與錄音,去河邊找鬼衣陶。 笑死柄瑰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的祖搓。 我是一名探鬼主播狱意,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拯欧!你這毒婦竟也來了详囤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤镐作,失蹤者是張志新(化名)和其女友劉穎藏姐,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體该贾,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡羔杨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了杨蛋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兜材。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖逞力,靈堂內(nèi)的尸體忽然破棺而出曙寡,到底是詐尸還是另有隱情,我是刑警寧澤寇荧,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布举庶,位于F島的核電站,受9級特大地震影響揩抡,放射性物質(zhì)發(fā)生泄漏户侥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一峦嗤、第九天 我趴在偏房一處隱蔽的房頂上張望蕊唐。 院中可真熱鬧,春花似錦烁设、人聲如沸刃泌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耙替。三九已至亚侠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俗扇,已是汗流浹背硝烂。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铜幽,地道東北人滞谢。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像除抛,于是被迫代替她去往敵國和親狮杨。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345