管中窺豹——從grabcut初探opencv縱向結構(一)

研究生的一年級上半學期期間也曾用matlab來做過一些作業以及一些數字圖像處理的練習,matlab的語法簡單直白,涉及多個領域的數學計算和建模仿真,實在強大的很,一定要挑毛病,也只能說總是覺得它有點兒憨。早就聽說過opencv在機器視覺方面的強大能力,委於精力有限,也一直沒有能夠上手。一年級下學期基本沒課了,開始課題研究階段,就藉機逐步的把opencv學習了起來,做應用,也會穿插着看大牛的心得筆記、opencv源代碼及相關論文,到現在算來也有2周時間了,自己也感覺漸漸的有了一些心得,記錄在此算是備忘。

廢話半天,進入正題吧,本文計劃主要完成幾件事兒:

1)快速瞭解一下圖割(Graph Cuts)的研究現狀

2)通過學習matlab對於gracut的的實現,初步瞭解opencv的縱向結構。

3)大致講一下grabcut的思想(如果還有餘力,或者文章還不算太長,就繼續完成)


圖割(Graph Cuts)

圖割是數字圖象處理中一個非常重要的承上啓下的環節,這個環節的工作是從圖像採集環節採集得到的圖像中提出感興趣的區域來,以便後續對這部分圖像進行有針對性的特徵分析和提取。下面先從偉大的維基皮迪亞翻譯一些有關於圖割的背景資料:

源起:1989年,法國杜倫大學(Durham University)的Seheult大牛在論文《Exact maximum a posteriori estimation for binary image》一文中首次在數字圖像領域提出了Graph Cuts這個概念的

小插曲,Durham University還真是挺美的

方法分類:

1、標準方法(Standard):在整個圖像S上最優化能量函數E(下面會解釋所謂的“能量函數”(energy function))

2、迭代方法(Iterated):a)利用K-means方法作以色彩爲參數參數作能量函數在圖像S上的最優化

3、動態方法(Dynamic)(Sorry,我不知道啥意思,求解釋

能量函數(energy function):

1、基於色彩(Ecolor)的,包括

1)直方圖(Histogram)

2)GMM(Gaussian Mixture Model)GMM就是OpenCV中的grabcut方法選用的能量函數模型

3)紋理(Texon)

2、基於關聯性(Ecoherence)的,包括:

1)基於像素(Pixel)的

我的理解是現在一般的圖像處理研究的待處理圖像都是採集自CCD的,由於CCD裏色彩傳感器橫平豎直的網格點陣狀的分佈,因此,所採集到的圖像也都是離散的點,這些點在採集到的圖像中最直接的聯繫就是鄰接關係,也就是我們常說的四方向圖和八方向圖

2)基於代價(Costs)的,包括一些細分類,包括:

a)局部密度梯度(local intensity gradient)

b)拉普拉斯零交叉(laplacian zero crossing)(這是啥?!求解釋

c)梯度方向(gradient direction)

d)色彩混合模型(color mixture model)

當前的研究存在的爭議(Criticism)(所謂的爭議,我覺得也就是存在問題的地方,其實也就是——潛在的研究方向哦!專門搞圖像處理研究的童鞋可以稍稍關注一下)

1、Metrication artifacts(youdao翻譯出來是“十進制文物”?!因爲辭不達意,就不作翻譯了。根據上下文的含義,我理解說的其實就是說的是在圖像採集的步驟中將圖像人工的“規則化”爲了像素網格(見前文解釋))

目前的研究已經提出了一些方法應對這個問題:

1)使用增加邊(additional edges)的方法(待查資料

2)在連續空間解決最大流(max-flow)的問題

注:前文所說的OpenCV中的grabcut方法是基於GMM模型作爲所謂的能量函數的,這種情況下的圖割問題的解其實就是對這個GMM模型在圖像S取得全局最優時,對於這個最優化問題的求解可以等價於對一個“最大流最小割”問題的求解

(所謂的“最大流最小割”問題這裏就不詳細解釋,感興趣的童鞋可以繼續去看書看資料,這裏只是把這個問題的結論給出來——連通圖的最大流(max-flow)等於最小割(min-cut)。其實就是說一個圖的最大流量受限於並且正好等於它的所有割點中流量最小的那個量(是不是有點兒升級版的“木桶原理”的感覺?))

2、“縮水”偏差(Shrinking bias)

因爲是尋求全局最優化的的過程等價於求取最小割問題的,因此(這個“因此”我並沒有理解):

1)可能會收斂於較小的圍線(contour)

注:這裏所謂的圍線,其實就是分割結果的邊界線

2)如果圖像中包含一些比較細小的物體(thin objects)——例如血管之類的,則分割效果不佳

2005年Vladimir Kolmogorov和Yuri Boykov對此問題作出一些推進(還沒看

3、Multiple Labels

通常的Graph Cuts只是考慮將圖像區域進行2分分類——即分爲前景區域和背景區域,多區域分割怎麼辦?

2001年Y. Boykov和O. Veksler及R. Zabih提出了一些解決方法(還沒看

4、Memory Usage

最大流最小割問題的算法存在着巨大內存空間佔用的問題,根據相關的研究空間複雜度爲24n+14m(其中n爲節點數,m爲邊數)


從grabcut初探opencv的縱向結構

(以下根據opencv-3.0.0作爲代碼根目錄)

/samples/cpp/grabcut.cpp是opencv自帶的grabcut的例子應用,我們的opencv之旅就從這裏開始吧。

編譯好opencv整個工程以後(cmake)從如下從不帶參數執行samples/cpp中的grabcut程序可以從幫助看到grabcut例子應用的主要功能。

通常的圖割算法可以理解爲生成一個二值蒙板,所謂的前景其實就是圖割完成後剪切出來的興趣區域(在生成的蒙板上體現爲白色區域——透過),所謂的背景就是相對的不感興趣的被算法剪去的部分(在生成的蒙板上體現爲黑色區域——遮擋)。

langrui@langruis-MBP:~/Downloads/opencv-3.0.0/samples/cpp$ ./cpp-example-grabcut

This program demonstrates GrabCut segmentation -- select an object in a region
and then grabcut will attempt to segment it out.
Call:
./grabcut <image_name>

Select a rectangular area around the object you want to segment

Hot keys: 
	ESC - quit the program
	r - restore the original image
	n - next iteration<span style="white-space:pre">					</span><span style="font-family: Arial, Helvetica, sans-serif;">//</span>開始下一次迭代尋優

	left mouse button - set rectangle<span style="white-space:pre">			</span><span style="font-family: Arial, Helvetica, sans-serif;">//</span><span style="font-family: Arial, Helvetica, sans-serif;">這個是劃定興趣區域,grabcut算法對於區域以外的部分全部劃爲背景(剪掉的部分)</span><span style="white-space:pre">
</span>
	CTRL+left mouse button - set GC_BGD pixels<span style="white-space:pre">		</span><span style="font-family: Arial, Helvetica, sans-serif;">//</span>勾畫背景
	SHIFT+left mouse button - set GC_FGD pixels<span style="white-space:pre">		</span><span style="font-family: Arial, Helvetica, sans-serif;">//</span>勾畫前景

	CTRL+right mouse button - set GC_PR_BGD pixels<span style="white-space:pre">		</span><span style="font-family: Arial, Helvetica, sans-serif;">//勾畫主要背景</span>
	SHIFT+right mouse button - set GC_PR_FGD pixels<span style="white-space:pre">		</span><span style="font-family: Arial, Helvetica, sans-serif;">//勾畫主要前景</span>

從程序的開頭部分可以看到grabcut對於opencv的引用關係。可以看到,包括了opencv中重要的三個部分:imgcodecs部分包含各種類型圖像資源的編解碼方法,負責圖像文件讀取和存儲;highgui部分負責高層(這裏所謂高層主要是體現在對操作系統這個“低”層的無關性上)的GUI(圖形用戶界面);imgproc中包括了包括grabcut算法在內的各種圖像處理的算法,是主要的圖像處理算法庫。

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace std;
using namespace cv;

在/samples/cpp/grabcut.cpp中最核心的調用imgproc庫中的grabCut方法進行圖像分割的部分是如下代碼段:

246 int GCApplication::nextIter()
247 {
248     if( isInitialized )
249         grabCut( *image, mask, rect, bgdModel, fgdModel, 1 );
250     else
251     {
252         if( rectState != SET )
253             return iterCount;
254 
255         if( lblsState == SET || prLblsState == SET )
256             grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK );
257         else
258             grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT );
259 
260         isInitialized = true;
261     }
262     iterCount++;
263 
264     bgdPxls.clear(); fgdPxls.clear();
265     prBgdPxls.clear(); prFgdPxls.clear();
266 
267     return iterCount;
268 }

圖像的讀取是基於imgcodecs庫的:

290     Mat image = imread( filename, 1 );

此外的多數代碼大多都是和接受和處理用戶交互及參數獲取相關的,而這些交互工作是基於highgui庫的。


不早了,要開始幹活了,先擺個opencv的主要模塊圖作爲本次的結束,下次繼續。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章