例程:classify_halogen_bulbs.hdev
在Halcon中模式匹配最成熟最常用的方式該署支持向量機了,在本例程中展示了使用支持向量機對鹵素燈的質量檢測方法。通過這個案例,相信大家可以對支持向量機的使用有一個更加清晰的了解。在相當多的檢測和識別的應用中,都可以使用相同的方法來解決分類問題。
圖1. 鹵素燈圖像
大致原理:
一、准備階段:描述樣本
1. 准備好兩組鹵素燈圖像樣本,好壞的各若干張圖像;
2. 對樣本圖像進行分割,獲取鹵素燈關鍵部位區域;
3. 選擇合適的對圖像的描述,作為識別的特征;
一、准備階段:構造分類器
1. 構造支持向量機:初始化支持向量機分類器所需的特征數量、核函數、類型數等參數;
2. 將樣本添加到分類器中;
3. 進行訓練,使分類器收斂;
二、識別階段:分類識別
1. 提取待測目標區域;
2. 提取分類所需的特征:與准備階段3中進行的操作相同;
3. 代入分類器進行分類。
上述在實際的操作過程中,准備階段樣本描述和構造分類器同時進行,即:將樣本圖像的特征提取和樣本添加到分類器中這兩步放在一個循環中完成。整個流程如下圖所示:
圖2. 支持向量機分類識別流程
圖中左邊部分是准備階段所做的工作。如圖所示,在使用SVM進行分類之前,首先需要構造分類器;構造完分類器之后,樣本通過SVM樣本描述循環體,被逐個進行特征提取后加入到待訓練的SVM分類器中;所有訓練樣本按照各自的類型添加結束后就進行訓練,使SVM收斂。
訓練之后的SVM就可以用於分類了,下面就進入識別階段。如圖右側所示,將待檢測的樣品圖像經過相同的特征提取過程后代入SVM分類器即可得到分類結果。由於SVM本質上是對提取的特征向量的特征空間進行划分來區別特征的類別,因此在識別階段使用的特征需要和准備階段的完全相同。這樣SVM在對待測樣本中提取的特征向量進行划分時才知道它具體落入哪一個類型所在的空間,也就知道該樣本的類型了。
對於使用,我們只要知道SVM是一個分類器,可以根據先驗知識將特征向量進行分類。如果想深入了解SVM是如何分類的,里面涉及到的原理可以通過下面的鏈接來查看:
http://files.cnblogs.com/sleepwalker/Ch12_pres%28SVM%29.pdf
幾乎所有使用SVM進行分類的流程大框架都遵循上圖,在不同的應用中使用SVM的區別就在於圖像描述的區別,如:Halcon學習筆記之支持向量機(一)中,樣本是每一個像素點,而特征向量是像素點的坐標。在本案例中,樣本是兩組圖像,而特征是分割后區域的若干個形態特征。
主流程代碼
首先黏貼出源代碼,這是Halcon當中例程中完整的代碼:
* This program uses an SVM classifier * to detect bad halogen bulbs. * * The training images have to be stored in sub directories * which are named after their class names. * * The procedure calculate_features may be edited to select different * features for the classification (if the number of features is changed, * you have to change the first parameter of create_class_svm as well) * get_system ('image_dir', HalconImages) get_system ('operating_system', OS) if (OS = 'Windows NT') tuple_split (HalconImages, ';', HalconImages) else tuple_split (HalconImages, ':', HalconImages) endif ReadOK := false dev_get_preferences ('suppress_handled_exceptions_dlg', SaveMode) dev_set_preferences ('suppress_handled_exceptions_dlg', 'true') for k := 0 to |HalconImages|-1 by 1 try read_image (Image, HalconImages[k] + '/halogen_bulb/halogen_bulb_01.png') ReadPath := HalconImages[k] + '/halogen_bulb/' ReadOK := true break catch (Exception) endtry endfor if (not ReadOK) disp_message (WindowHandle, 'Could not find the images in $HALCONIMAGES', 'window', -1, -1, 'black', 'true') stop () endif dev_set_preferences ('suppress_handled_exceptions_dlg', SaveMode) read_image (Image, 'halogen_bulb/halogen_bulb_01.png') get_image_pointer1 (Image, Pointer, Type, Width, Height) dev_close_window () dev_open_window (0, 0, Width/2, Height/2, 'black', WindowHandle) set_display_font (WindowHandle, 14, 'courier', 'true', 'false') * ClassNames := ['good','bad','none'] Colors := ['forest green','red','red'] Nu := [0.05] KernelParam := [0.02] * * Create an SVM classifier create_class_svm (7, 'rbf', KernelParam, Nu, |ClassNames|, 'one-versus-one', 'principal_components', 5, SVMHandle) * * Add samples add_samples_to_svm (ClassNames, SVMHandle, WindowHandle, ReadPath) dev_clear_window () * * Train the classifier disp_message (WindowHandle, 'Training...', 'window', -1, -1, 'black', 'true') train_class_svm (SVMHandle, 0.001, 'default') disp_message (WindowHandle, 'Training completed', 'window', -1, -1, 'black', 'true') disp_continue_message (WindowHandle, 'black', 'true') stop () * * Classify halogen bulbs classify_regions_with_svm (SVMHandle, Colors, ClassNames, ReadPath) * * Clear the classifier from memory clear_class_svm (SVMHandle)
以上這是Halcon中案例的源代碼,代碼稍微有點長,但是其中很大篇幅代碼與算法關系不大,下面進行詳細介紹。
程序詳解
初始化系統
首先我們可以看到截圖所示部分的代碼,所占篇幅較大。這部分代碼的目的僅僅是初始化環境,並對樣本圖像的目錄進行檢查,這里不再對內容進行過多介紹。值得注意的是,其中對try-catch的使用在其它例程中不多見,但是實際應用中還是很有必要的,大家在寫代碼的時候不妨可以參考一下。
准備階段
初始化
下面截圖所示代碼為准備階段所做的事情:構造分類器、循環添加樣本、訓練分類器。
第一行定義了分類器所要分辨的類型:good, bad, none;
第二行定義了在輸出時候不同結果顯示的顏色;
第三和第四行是構造的分類器參數;
第五行,如注釋所示,是構造SVM分類器;
對於前兩行定義的元組,實質是一個枚舉類型。因為在Halcon中,類型輸出實際是一個整數,即諸如:0,1,2……的整數。因此如果輸出是0,則對應的類型是good;輸出1對應是bad;輸出2對應的類型是none。而在顯示的時候,同樣的,可以使用Colors元組中相應位置的數據作為顯示參數,用於顯示不同顏色的字符或者區域。
通過create_class_svm構造SVM分類器之后需要添加樣本進行訓練,下面就進入外部過程add_sample_to_svm。如下圖所示,通過鼠標右鍵,可以查看外部過程詳細定義,該外部過程定義如下:
add_sample_to_svm:
這是一個循環,每次循環完成的任務為:
1. 讀取下一幀樣本圖像(Image);
2. 使用固定閾值分割后提取待測區域(Region);
3. 計算特征向量(Features);
4. 將特征向量按照類型加入SVM中;
圖3. 分割后的區域
calculate_features同樣也是一個外部過程,該外部過程定義如下:
calculate_features:
從定義中,我們可以知道特征向量的選取,包括:面積(Area)、密實度(Compactness)、四個不變矩特征(PSI1,PSI2,PSI3,PSI4)和凸度(Convexity)。這些特征都屬於區域的形態特征,最后將這些特征合並成一個實數型的特征向量Features,作為本過程的最終運算結果:
圖4. 特征示例
訓練SVM
添加樣本后就開始訓練SVM分類器,這一步Halcon僅通過一個tran_class_svm就能夠完成,訓練過程實質就是使用構造SVM時定義的核函數(此處為rbf)在高維特征空間尋找最優的分界面,將特征空間划分成不同類型(此處為good、bad、none三類)。訓練過程是SVM的核心,也是需要進行大量運算的過程,因此在這一個算子上,可能會耗費比較長的時間。
具體如何划分,原理感興趣的朋友可以下載上面的鏈接中的pdf文件進行研究。
識別階段
到了識別階段,就是對待測樣本進行分類了,分類結果本案例中共有三類:good、bad、none。整個識別過程被封裝在外部過程classify_regions_with_svm中:
classify_regions_with_svm:
從程序中可以看到,識別過程經歷了與樣本添加過程中相同的分割和特征提取。將提取到的特征向量代入SVM分類器就就能得出分類結果(Class)了。代入分類器的算子為classify_class_svm。從這里我們也可以看到,對SVM分類器實質是在對提取到的特征向量進行分類。
圖5. 識別結果圖
總結
整體來說,SVM分類到這里基本上已經結束,其它部分顯示的代碼就不在進行介紹了,相信大家也看得懂。這里我沒有對參數的配置進行介紹,只介紹了整個流程。對於參數的解釋,使用Halcon的朋友通過查詢手冊要來得更加方便,也更加准確。