使用HALCON进行图像分类——图像分类(系统讲解,附模板例程精讲)
利用HALCON對圖像進行分類
- 1.基礎知識
 - 1.1分類器的作用與使用范圍
 - 1.2分類器的種類
 - 1.3 分類器特點
 - 1.4 圖像分類的一般流程
 
- 2.特征的分類
 - 2.1 MLP分類器的關鍵算子
 - (1)創(chuàng)建分類器——create_class_mlp算子
 - (2)將單個樣本添加到MLP分類器中——add_sample_class_mlp算子
 - (3)進行樣本的訓練——train_class_mlp算子
 - (4)評估一個算子屬于某個類別的概率——evaluate_class_mlp算子
 - (5)使用訓練好的分類器進行分類——classify_class_mlp算子
 - (6)釋放分類器——clear_class_mlp算子
 
- 2.2 HALCON相關示例程序精解
 
- 3.光學字符識別
 - 3.1 一般步驟
 - 3.2 HALCON相關示例程序
 
1.基礎知識
1.1分類器的作用與使用范圍
分類器的作用是將目標對象指定為已給的多個類別中的一個。例如一張圖中包含了幾種形狀不同的物體,我們可以通過分別對每一種形狀對應樣本的區(qū)域的某些特征值,并告訴它每一類形狀的這些樣本屬于哪種類別來進行訓練,完成訓練后,再輸入待判斷物體的形狀區(qū)域的相應特征值,這時分類器便可以根據(jù)之前的訓練成果,來對輸入?yún)^(qū)域進行判斷,并給出判斷的結果。
這里,我對區(qū)域進行了加粗,是因為需要大家知道,分類器所需要的輸入是區(qū)域的特征值,而不是單純的原始圖像,無論是進行訓練,還是進行識別,它的輸入始終都是區(qū)域的特征值。因此,進行分類器操作之前,對原始圖像進行一些預處理以及圖像分割來得到我們需要輸入的目標區(qū)域是必須的。具體如何分割,則需要具體場景具體分析。
1.2分類器的種類
Halcon提供了多種分類器,比較重要的分類器有
 (1)基于神經(jīng)網(wǎng)絡,特別是多層感知器的MLP分類器
 (2)基于支持向量機的SVM分類器
 (3)基于高斯混合模型的GMM分類器
 (4)基于k近鄰的k-NN分類器
1.3 分類器特點
(1) MLP分類器
 MLP分類器分類速度快,但訓練速度慢,對內存的要求低,支持多維特征空間,特別適合需要快速分類并且支持離線訓練的場景,但不支持缺陷檢測。
 (2)SVM分類器
 分類檢測的速度快,當向量維度低時速度最快,但比MLP分類器慢,盡量訓練速度比MLP分類器快得多。其對內存的占用取決于樣本的數(shù)量,如果有大量的樣本,如字符庫這樣的樣本需要訓練,分類器將變得非常龐大。
 (3) GMM分類器
 訓練速度和檢測速度都很快,特別是類別較少時速度特別快,支持異常檢測,但不適用于高維度特征檢測。
 (4)k-NN分類器
 訓練速度非常快,分類速度比MLP分類器慢,適合缺陷檢測和多維度特征分類,但對內存的需求較高。
多數(shù)情況下,上面四種分類器都是可以勝任需求的。
1.4 圖像分類的一般流程
(1)準備樣本圖片
 (2)對樣本圖片進行處理(如二值化、圖像分割等),提取出目標區(qū)域
 (3)分析目標特征,選取可以用來將不同類別區(qū)分開來的幾種特征值作為特征向量以訓練分類器
 (2)創(chuàng)建分類器
 (3)訓練分類器
 (4)檢測待測目標對象,分類器根據(jù)訓練得到的類別的邊界條件判斷檢測對象屬于哪個分類
 (5)清除分類器,釋放內存
總的來說,針對不同的分類任務,需要選擇一組合適的特征和合適的分類器,以及合適的訓練樣本。
2.特征的分類
2.1 MLP分類器的關鍵算子
(1)創(chuàng)建分類器——create_class_mlp算子
create_class_mlp( : : NumInput, NumHidden, NumOutput, OutputFunction, Preprocessing, NumComponents, RandSeed : MLPHandle)
該算子除了MLPHandle是輸出參數(shù)以外,其余都是輸入?yún)?shù),介紹如下:
 NumInput:用于訓練和分類的特征空間的維度數(shù)。默認是20,也可以更大甚至500。
 NumHidden:表示神經(jīng)網(wǎng)絡中隱藏層的單元數(shù)量。改值會明顯地影響分類結果,需要謹慎設置。其取值范圍與NumInput及NumOutput相似。其值越小,超平面就越簡單,有時能夠得到更好的效果;如果取值過大,反而會有過擬合的可能,比如可能將噪聲點用于訓練分類器的邊界,這時如果待測對象不包括這些非關鍵的點,則可能分類失敗。
 NumOutput:表示輸出的分類數(shù)量,比如對兩種物體進行分類,即為2,對三種物體分類即為3。
 OutputFunction:表示神經(jīng)網(wǎng)絡的輸出單元使用的函數(shù),可選的有softmax、logistic、linear。絕大多數(shù)情況下,輸出函數(shù)都可以使用softmax。logistic用于處理多個邏輯獨立的屬性的分類問題,非常少見。linear用于最小二乘法,而不是用于分類,可以忽略。
 Preprocessing:該參數(shù)表示在訓練與分類前對特征向量進行預處理。預處理可以加快訓練或者分類的速度,有時也有助于提升分類的準確度。其可選方法有四種。選擇none時不進行任何預處理,大多數(shù)情況下,選擇normalization,表示將特征向量歸一化為0至1的數(shù)。這種處理既不會改變特征向量的長度,又能有效提升速度,因此是預處理的首選。如果特征向量是高度相關的,可以選擇principal_components
 NumComponents:在Preprocessing選擇canonical_variates或者principal_components時使用。因為這兩種預處理方法可能會減少特征空間的維度,NumComponents就表示減少后的特征向量的維度。
 RandSeed:用于初始化MLP中的權重值,該值表示隨機數(shù)種子數(shù),存儲在RandSeed中。
 MLPHandle:唯一的輸出參數(shù)。這是分類器的句柄,用于后續(xù)對分類器進行各種操作,如調用、修改、刪除等。
(2)將單個樣本添加到MLP分類器中——add_sample_class_mlp算子
add_sample_class_mlp( : : MLPHandle, Features, Target : )
MLPHandle:表示分類器的句柄
 Feaures:表示輸入樣本的特征向量。該向量類似于一個數(shù)組,其中的每一個值表示一種特征,其維度數(shù)應當與create_class_mlp中的NumInput的值相同。
 Target:設置類別的標識號。它可以設置的值的個數(shù)與create_class_mlp中的NumOutput的值相同。比如有三種類型的物體需要進行圖像分類,那么Target對應每種形狀時就可以分別設置為0、1、2。當然也可以設置為其他數(shù)字。Target表示類別的標識ID,每一個Traget即代表是一種類別。
(3)進行樣本的訓練——train_class_mlp算子
train_class_mlp( : : MLPHandle, MaxIterations, WeightTolerance, ErrorTolerance : Error, ErrorLog)
MaxIterations:表示優(yōu)化算法的最大迭代次數(shù),默認為200。多數(shù)情況下,算法會在迭代了MaxIterations次后結束。100~200的次數(shù)一般都是足夠的。
 WeightTolerance:表示優(yōu)化算法的兩次迭代之間的權重差異閾值。如果權重小于該值,優(yōu)化算法將終止。一般默認為1,且無需改變。
 ErrorTolerance:表示優(yōu)化算法的兩次迭代之間的誤差均值的閾值。均值小于該值,算法也會終止。一般默認為0.01,且無需改變。
 Error:表示MLP在最佳權重下的訓練數(shù)據(jù)的平均誤差。
 ErrorLog:該參數(shù)將MLP的訓練數(shù)據(jù)的平均誤差作為迭代次數(shù)返回。它用于判斷是否應該使用不同的RandSeed對同樣的樣本進行二次訓練。合適的情況下,ErrorLog應當是在開始時急劇下降,后越來越平穩(wěn)。如果是從頭到尾其值都走勢陡峭,則通常應重新設置參數(shù)重新訓練。
(4)評估一個算子屬于某個類別的概率——evaluate_class_mlp算子
evaluate_class_mlp( : : MLPHandle, Features : Result)
Features:表示輸入的待評估的特征向量。這里的特征向量的維度與結構應當與add_sample_class_mlp中的訓練樣本的特征向量相同。
 Result:表示由MLP評估后輸出的結果。
(5)使用訓練好的分類器進行分類——classify_class_mlp算子
classify_class_mlp( : : MLPHandle, Features, Num : Class, Confidence)
完成創(chuàng)建與訓練后的分類器便可以對未知對象進行分類了。
 Features:輸入的待評估的特征向量。
 Num:想要尋找的最佳分類的數(shù)量。如設置為1則只返回概率最大的那個類別,設置為2則將概率前兩名的兩個類別都返回。
 class:輸出所尋找的類別ID,若Num為1,則返回一個ID,Num為2則返回兩個,每個值都為add_sample_class_mlp中Target設置的值之一,即代表每個類別的ID。
(6)釋放分類器——clear_class_mlp算子
clear_class_mlp (MLPHandle)
根據(jù)分類器的句柄,將完成分類任務后不需要在使用的分類器清除釋放。同時釋放MLP分類器所占用的內存資源。
2.2 HALCON相關示例程序精解
這里使用的是HALCON的一個相關例程,是一個非常標準的圖像分類模板,筆者在注釋中對本例程進行了詳細的講解,方便初學者學習。
另外,筆者對例程進行了稍微的改動。主要是原始例程編寫了幾個本地函數(shù)(即自定義函數(shù),它使用已存在算子對多個步驟進行了封裝,對于簡化代碼與提高代碼模塊化有很大作用),雖然合理但是不方便初學者查閱理解,因此在下述代碼中筆者用原始算子替換了原來的本地函數(shù),本地函數(shù)被注釋。這樣方便每一個步驟的精確講解,也方便大家對程序進行改動移植而不出錯。
本地函數(shù)包括segment,add_samples,get_features,classify,筆者已注釋,讀者可自行刪除。
dev_update_off () dev_close_window () dev_open_window (0, 0, 640, 480, 'black', WindowHandle) set_display_font (WindowHandle, 16, 'mono', 'true', 'false') dev_set_colored (6) dev_set_draw ('margin') dev_set_line_width (3) * *一、創(chuàng)建mlp分類器。 *用于訓練和分類的特征向量維度數(shù)為6,神經(jīng)網(wǎng)絡中隱藏層為5,共需要對3種類別進行分類,其他參數(shù)參考文章2.1 MLP分類器的關鍵算子 create_class_mlp (6, 5, 3, 'softmax', 'normalization', 3, 42, MLPHandle) * *二、添加樣本到分類器 *循環(huán)讀取每一個圖片文件,對每一個圖片進行二值化圖像分割,獲取每個區(qū)域的特征向量與各自所對應的類別作為樣本添加入分類器 FileNames := ['nuts_01','nuts_02','nuts_03','washers_01','washers_02','washers_03','retainers_01','retainers_02','retainers_03'] *這里按照圖片順序將每張圖片的類別ID(即add_sample_class_mlp中的Target)存放在數(shù)組Classes當中,方便在循環(huán)中自動根據(jù)圖片順序選擇相應的類別ID Classes := [0,0,0,1,1,1,2,2,2] *對于每一張圖片,將進行以下操作 for J := 0 to |FileNames| - 1 by 1read_image (Image, 'rings/' + FileNames[J])dev_display (Image)dev_set_colored (6)*segment (Image, Objects)*二值化分割圖像,提取圖像中較暗的部分("dark"),即零件部分,'max_separability'表示在直方圖中對最大的可分性進行分割,*UsedThreshold是算法自動計算出用于圖像分割的閾值,作為輸出參數(shù)返回binary_threshold (Image, Objects, 'max_separability', 'dark', UsedThreshold)*合并像素相連部分成為一個個區(qū)域 connection (Objects, ConnectedRegions) *填充每個區(qū)域(零件)中的孔或和縫等,形成新的實心區(qū)域。 fill_up (ConnectedRegions, Objects)dev_display (Objects)*設置字體顏色,顯示當前循環(huán)位置,方便觀察dev_set_color ('black')disp_message (WindowHandle, 'Add Sample ' + J + ', Class Index ' + Classes[J], 'window', 10, 10, 'black', 'true') * add_samples (Objects, MLPHandle, Classes[J])*計算區(qū)域的個數(shù),也就是一張圖像中零件的個數(shù)。count_obj (Objects, Number)*對于一張圖片中的每一個處理后的實心區(qū)域(零件),將進行以下操作for k := 1 to Number by 1 *選擇第k個區(qū)域(零件),計算該區(qū)域的相關特征參數(shù),作為特征向量準備輸入給分類器select_obj (Objects, Region, k)* get_features (Region, Features)select_obj (Region, SingleRegion, 1) *與圓的相似度Circularity,roundness則由區(qū)域的輪廓與區(qū)域中心之間的平均距離(Distance)及與平均距離的偏差(Sigma)組合公式而來。circularity (SingleRegion, Circularity)roundness (SingleRegion, Distance, Sigma, Roundness, Sides)*這個算子用于計算區(qū)域幾何特性,輸出4個代表區(qū)域幾何特性的參數(shù)。moments_region_central_invar (SingleRegion, PSI1, PSI2, PSI3, PSI4) *前面通過三個算子得到了Circularity,roundness, PSI1, PSI2, PSI3, PSI4共6個參數(shù),使用這六個特征參數(shù)組合成特征向量FeaturesFeatures := [Circularity,Roundness,PSI1,PSI2,PSI3,PSI4] *將得到的特征向量作為樣本添加進分類器,并指明對應的類別ID,即Classes[J]add_sample_class_mlp (MLPHandle, Features, Classes[J]) endfor *一張圖片中多個區(qū)域處理的循環(huán)結束disp_continue_message (WindowHandle, 'black', 'true')stop () endfor * 多張圖片的處理的循環(huán)結束* 三.利用添加好的樣本特征向量組,訓練分類器 dev_clear_window () dev_set_color ('black') disp_message (WindowHandle, 'Training...', 'window', 10, 10, 'black', 'true') *開始訓練分類器 train_class_mlp (MLPHandle, 200, 1, 0.01, Error, ErrorLog) *訓練完成后,清除分類器中的樣本數(shù)據(jù),釋放占用內存資源 clear_samples_class_mlp (MLPHandle) *出現(xiàn)文字提示訓練完成 disp_message (WindowHandle, 'Training... completed', 'window', 10, 10, 'black', 'true') disp_continue_message (WindowHandle, 'black', 'true') stop () * * 四.實現(xiàn)分類器分類功能 *dev_set_draw ('fill') *對于每一張圖片,進行目標區(qū)域的獲取與每一個區(qū)域特征向量的獲取,輸入給分類器進行類別的判斷 for J := 1 to 4 by 1read_image (Image, 'rings/mixed_' + J$'02d')dev_display (Image)dev_set_color ('black')dev_set_draw ('margin')disp_message (WindowHandle, 'Classifiy Image' + J, 'window', 10, 10, 'black', 'true')*segment (Image, Objects)*對每張圖片進行區(qū)域分割,得到每個零件的區(qū)域并進行填充,具體步驟含義參考創(chuàng)建mlp分類器時的相同代碼binary_threshold (Image, Objects, 'max_separability', 'dark', UsedThreshold) connection (Objects, ConnectedRegions) fill_up (ConnectedRegions, Objects)*classify (Objects, MLPHandle, Classes)*完成對每個區(qū)域(也就是每一個零件)的提取后,分別計算每個區(qū)域的特征向量并輸入給分類器進行分類,分類結果存儲在Classes數(shù)組當中count_obj (Objects, Number) Classes := [] for k := 1 to Number by 1*下面計算特征向量步驟與創(chuàng)建mlp分類器部分相應代碼相同,自行向前查閱。select_obj (Objects, Region, k)*get_features (Region, Features)select_obj (Region, SingleRegion, 1) circularity (SingleRegion, Circularity) roundness (SingleRegion, Distance, Sigma, Roundness, Sides) moments_region_central_invar (SingleRegion, PSI1, PSI2, PSI3, PSI4) Features := [Circularity,Roundness,PSI1,PSI2,PSI3,PSI4] *得到特征向量Features輸入分類器,進行分類,返回一個最可能的結果Class,并給出置信度Confidenceclassify_class_mlp (MLPHandle, Features, 1, Class, Confidence) *該語法含義是將每次循環(huán)中class的值添加入Classes當中,相當于很多語言中的數(shù)組的.push()方法,以此將分類結果class存儲在數(shù)組Classes *當中,如Class為0,則對應第一類,Class為2,則對應第三類。Classes := [Classes,Class] endfor *結束對一張圖片中所有區(qū)域(零件)的分類 stop()*下面是針對每張圖片分類完成后的結果,進行可視化顯示disp_obj_class (Objects, Classes)count_obj (Objects, Number)*采用三種不同顏色放在數(shù)組中,根據(jù)類別ID(0,1,2),來選擇數(shù)組中的顏色 Colors := ['yellow','magenta','green'] for l := 1 to Number by 1select_obj (Objects, Region, l)dev_set_color (Colors[Classes[l - 1]])dev_display (Region) endforif (J < 4)* 判斷四張圖片未處理完時,每一張?zhí)幚硗瓿珊?#xff0c;暫停進行提示,再手動進入下一張的處理disp_continue_message (WindowHandle, 'black', 'true')stop ()endif endfor *四張圖片全部處理完成 stop () * *5.清除分類器,釋放分類器所占用的內存 clear_class_mlp (MLPHandle)其他分類器的操作步驟也可以參考MLP分類器的操作步驟,希望讀者結合HALCON的相關自帶例程,自行發(fā)現(xiàn)相通之處。
3.光學字符識別
3.1 一般步驟
(1)字符的訓練
①讀取樣本圖像,并對樣本中的已知字符進行區(qū)域分割,分割的單位是單個字符的包圍區(qū)域這時可以使用draw_rectangle1等算子選擇出單個字符的區(qū)域
 ②將分割出的區(qū)域和對應的字符名稱存儲在訓練文件中。可以使用append_ocr_class_mlp算子,將字符區(qū)域存在指定的以“.trf”結尾的訓練文件中。
 ③檢查訓練文件中的對應關系,即圖像與字符的名稱一一對應。
 ④訓練分類器。創(chuàng)建分類器后開始訓練。
 ⑤保存分類器
 ⑥清除分類器
(2)字符檢測
①讀取分類器文件。
 ②對待檢測的字符進行區(qū)域分割,提取出獨立的字符區(qū)域。
 ③使用分類器進行分類。
 ④清除分類器
Halcon根目錄下的ocr文件夾中內置了許多針對數(shù)字、字母和噴碼等類字符的分類器。針對多種標準的、非中文的字符,可以直接調用這些訓練好的分類器文件而無需自己進行訓練。手寫體或者中文字符則需要自己進行離線訓練。
3.2 HALCON相關示例程序
這里僅放置Halcon實例程序源代碼,具體步驟參考之前的mlp分類器分類程序講解。分類步驟及思想都是想通的。
(1)字符的訓練
* The font is used in "bottle.hdev" * * * Step 0: Preparations FontName := 'bottle' * * Step 1: Segmentation dev_update_window ('off') read_image (Bottle, 'bottle2') get_image_size (Bottle, Width, Height) dev_close_window () dev_open_window (0, 0, 2 * Width, 2 * Height, 'black', WindowID) set_display_font (WindowID, 27, 'mono', 'true', 'false') threshold (Bottle, RawSegmentation, 0, 95) fill_up_shape (RawSegmentation, RemovedNoise, 'area', 1, 5) opening_circle (RemovedNoise, ThickStructures, 2.5) fill_up (ThickStructures, Solid) opening_rectangle1 (Solid, Cut, 1, 7) connection (Cut, ConnectedPatterns) intersection (ConnectedPatterns, ThickStructures, NumberCandidates) select_shape (NumberCandidates, Numbers, 'area', 'and', 300, 9999) sort_region (Numbers, FinalNumbers, 'first_point', 'true', 'column') dev_display (Bottle) dev_set_color ('green') dev_set_line_width (2) dev_set_shape ('rectangle1') dev_set_draw ('margin') dev_display (FinalNumbers) * * Step2: Training file generation TrainingNames := ['0','1','0','8','9','4'] TrainingFileName := FontName + '.trf' sort_region (FinalNumbers, SortedRegions, 'first_point', 'true', 'column') shape_trans (SortedRegions, RegionTrans, 'rectangle1') area_center (RegionTrans, Area, Row, Column) MeanRow := mean(Row) dev_set_check ('~give_error') delete_file (TrainingFileName) dev_set_check ('give_error') for I := 0 to |TrainingNames| - 1 by 1select_obj (SortedRegions, CharaterRegions, I + 1)append_ocr_trainf (CharaterRegions, Bottle, TrainingNames[I], TrainingFileName)disp_message (WindowID, TrainingNames[I], 'image', MeanRow - 40, Column[I] - 6, 'yellow', 'false') endfor * * Step3: Training CharNames := uniq(sort(TrainingNames)) create_ocr_class_mlp (8, 10, 'constant', 'default', CharNames, 10, 'none', 10, 42, OCRHandle) trainf_ocr_class_mlp (OCRHandle, TrainingFileName, 200, 1, 0.01, Error, ErrorLog) write_ocr_class_mlp (OCRHandle, FontName) clear_ocr_class_mlp (OCRHandle)(2)字符的在線檢測
* * Step 0: Preparations * Specify the name of the font to use for reading the date on the bottle. * It is easiest to use the pre-trained font Universal_0-9_NoRej. If you * have run the program bottlet.hdev in this directory, you can activate * the second line to use the font trained with this program. FontName := 'Universal_0-9_NoRej' * FontName := 'bottle' * * Step 1: Segmentation dev_update_window ('off') read_image (Bottle, 'bottle2') get_image_size (Bottle, Width, Height) dev_close_window () dev_open_window (0, 0, 2 * Width, 2 * Height, 'black', WindowID) set_display_font (WindowID, 16, 'mono', 'true', 'false') dev_display (Bottle) disp_continue_message (WindowID, 'black', 'true') stop () * * Create Automatic Text Reader and set some parameters create_text_model_reader ('auto', FontName, TextModel) * The printed date has a significantly higher stroke width set_text_model_param (TextModel, 'min_stroke_width', 6) * The "best before" date has a particular and known structure set_text_model_param (TextModel, 'text_line_structure', '2 2 2') * * Read the "best before" date find_text (Bottle, TextModel, TextResultID) * * Display the segmentation results get_text_object (Characters, TextResultID, 'all_lines') dev_display (Bottle) dev_display (Characters) stop () * Display the reading results get_text_result (TextResultID, 'class', Classes) area_center (Characters, Area, Row, Column) disp_message (WindowID, Classes, 'image', 80, Column - 3, 'green', 'false') * * Free memory clear_text_result (TextResultID) clear_text_model (TextModel)內容粗淺,敬請各位讀者朋友評論私信,批評指正!
總結
以上是生活随笔為你收集整理的使用HALCON进行图像分类——图像分类(系统讲解,附模板例程精讲)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: XJad反编译工具
 - 下一篇: Siemens 软件下载