前言:
==========================================================
分类器相对于深度学习来讲是一种古老传统的图片处理技术。halcon中常见的有四类分类器:
MLP(多层神经网络neural Nets)
SVM(支持向量机)
K-NN(K-最邻近)
GMM(高斯混合类型)
分类器的应用领域主要是下面这些:
image segmentation 图像分割
object recognition 对象识别
quality control 质量控制
novelty detection 缺陷检测
optical character recognition(OCR) 光学字符识别
勇哥第一次见到分类器的视觉项目是锂电池的极片缺陷检测,效果还不错。
这两年深度学习火起来后,发现深度学习完成上面所说的领域的应用更容易,效果也更好。
但深度学习对硬件要求太高,你把IPC加装个一百多W的显卡很多时候是不现实的。
如果你用cpu来跑,会发现速度乎快乎慢,cpu全部内核会100%被占用。
分类器相对于深度学习来讲不吃硬件,所以相对来讲算是轻量级的应用。
==========================================================
下面的实例程序比较了不同参数的OCR支持向量机对人工数据的识别率。
字母图像随机失真,并作为训练数据反馈给三种不同的SVM训练变体:
1. 带默认设置的SVM
2. 人工优化设置的SVM(功能,nu,gamma(Kernelparameter))
3. 基于nu和gamma自动估计特征的SVM
“term tuning”在这里仅指识别率。本例中不考虑执行时间。
最佳参数集的估计可能需要相当长的时间,因为它是在非常高维空间上的定向搜索(取决于可能的特征的数量以及是否必须估计nu和gamma)。
对于“最佳参数估计”这个功能可以参考勇哥之前的文章:http://47.98.154.65/?id=1640
这个例子演示了分类器的自动参数估计和自动特征选择——在本例中是一个用于OCR的SVM(支持向量机)分类器

这个警告是:
警告:F5将启动自动功能选择 这可能需要一段时间(最多几个小时)! 在Intel i5(4核,3.3GHz)上大约15分钟的计算时间。 如果您现在没有时间请取消程序执行,稍后再来测试
勇哥这个破i5笔记本不行,等到花儿都谢了,还是用台式机跑吧!

耗时算子是:select_feature_set_trainf_svm ,它是用来自动选择适合的特征。

来看看勇哥的xeon服务器,20核居然跑了24分钟,果然还是很垃圾哦。
应该是单核速度太慢的原因。

现在将在严重扭曲的字符上测试所有三个分类器,并计算错误率。
可以看到,自动训练的分类器的性能接近手动优化的分类器。

测试源码:
dev_update_off ()
dev_close_window ()
dev_open_window (0, 0, 500, 500, 'black', WindowHandle)
dev_set_color ('green')
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
set_system ('seed_rand', 42)
get_tmp_dir (TmpDir)
TrainFile := TmpDir + '/letters_autosvm.trf'
TrainFileBig := TmpDir + '/letters_big_autosvm.trf'
*
* 创建原始训练样本并将其存储在训练文件中.
dev_clear_window ()
dev_set_part (0, 0, 499, 499)
*这个例子演示了分类器的自动参数估计和自动特征选择——在本例中是一个用于OCR的SVM(支持向量机)分类器
Message := 'This example demonstrates the'
Message[1] := 'automatic parameter estimation and'
Message[2] := 'automatic feature selection for'
Message[3] := 'classifiers - in this case a SVM'
Message[4] := '(support vector machine) classifier'
Message[5] := 'for OCR.'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_message (WindowHandle, 'Please wait while ...', 'window', 200, 12, 'white', 'false')
disp_message (WindowHandle, ' ... creating initial samples ... ready', 'window', 230, 12, 'white', 'false')
gen_initial_trainfile (TrainFile)
read_ocr_trainf_names (TrainFile, CharClasses, CharacterCount)
read_ocr_trainf (Characters, TrainFile, CharacterNames)
dev_set_check ('~give_error')
delete_file (TrainFileBig)
dev_set_check ('give_error')
*创建初始样本
disp_message (WindowHandle, ' ... creating initial samples ... ready', 'window', 230, 12, 'white', 'false')
*添加变形的样本
disp_message (WindowHandle, ' ... adding distorted samples ...', 'window', 260, 12, 'white', 'false')
count_obj (Characters, NumChars)
for Index := 1 to 2 by 1
for J := 0 to NumChars - 1 by 1
select_obj (Characters, Char, J + 1)
full_domain (Char, CharFull)
gen_distorted_character (CharFull, CharDistort, 7)
Class := CharacterNames[J]
threshold (CharDistort, Region, 0, 128)
area_center (Region, Area, Row, Column)
if (Area < 10)
continue
endif
append_ocr_trainf (Region, CharDistort, Class, TrainFileBig)
full_domain (CharDistort, ImageFull)
get_image_size (CharFull, Width, Height)
endfor
endfor
* Train the SVMs
disp_message (WindowHandle, ' ... adding distorted samples ... ready', 'window', 260, 12, 'white', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()
dev_set_part (0, 0, 499, 499)
Message := 'Train SVM with default settings ... '
disp_message (WindowHandle, Message, 'window', 12, 12, 'white', 'false')
create_ocr_class_svm (8, 10, 'bilinear', 'default', CharClasses, 'rbf', 0.02, 0.05, 'one-versus-one', 'normalization', 10, OCRHandleSVMDefault)
count_seconds (S1)
trainf_ocr_class_svm (OCRHandleSVMDefault, TrainFileBig, 0.001, 'default')
count_seconds (S2)
Message := Message + (S2 - S1)$'3.2' + 's'
disp_message (WindowHandle, Message, 'window', 12, 12, 'white', 'false')
Message[1] := ' \nTrain SVM manually optimized ... '
disp_message (WindowHandle, Message, 'window', 12, 12, 'white', 'false')
create_ocr_class_svm (8, 10, 'bilinear', ['gradient_8dir','pixel','projection_horizontal','foreground_grid_16','phi','moments_region_2nd_invar','chord_histo','ratio'], CharClasses, 'rbf', 0.001, 0.03, 'one-versus-one', 'normalization', 10, OCRHandleSVMOpt)
count_seconds (S1)
trainf_ocr_class_svm (OCRHandleSVMOpt, TrainFileBig, 0.001, 'default')
count_seconds (S2)
Message[1] := ' \nTrain SVM manually optimized ... ' + (S2 - S1)$'3.2' + 's'
disp_message (WindowHandle, Message, 'window', 12, 12, 'white', 'false')
count_seconds (S2)
Message[2] := ' \nAutomatic parameter estimation ... '
disp_message (WindowHandle, Message, 'window', 12, 12, 'white', 'false')
*警告:F5将启动自动功能选择
*这可能需要一段时间(最多几个小时)!
*在Intel i5(4核,3.3GHz)上大约15分钟的计算时间。
*如果您现在没有时间请取消程序执行,稍后再来测试
Warning := 'Warning: F5 will start the'
Warning[1] := 'automatic feature selection.'
Warning[2] := 'This may take a while (up to hours)!'
Warning[3] := 'On an Intel i5 (4 cores, 3.3GHz) expect'
Warning[4] := 'about 15 minutes of calculation time.'
Warning[5] := ' '
Warning[6] := 'If you don\'t have the time now'
Warning[7] := 'please cancel the program and'
Warning[8] := 'come back later.'
Warning[9] := ' '
Warning[10] := 'If you want to continue, press F5.'
disp_message (WindowHandle, Warning, 'window', 150, 20, 'white', 'red')
stop ()
dev_clear_window ()
disp_message (WindowHandle, Message, 'window', 12, 12, 'white', 'false')
Status := 'Performing automatic feature selection ...'
Status[1] := ' \nPlease check the HDevelop status bar'
Status[2] := 'for progress information.'
disp_message (WindowHandle, Status, 'window', 200, 12, 'yellow', 'false')
count_seconds (S1)
select_feature_set_trainf_svm (TrainFileBig, ['zoom_factor','ratio','width','height','foreground','foreground_grid_9','foreground_grid_16','anisometry','compactness','convexity','moments_region_2nd_invar','moments_region_2nd_rel_invar','moments_region_3rd_invar','moments_central','phi','num_connect','num_holes','projection_horizontal','projection_vertical','projection_horizontal_invar','projection_vertical_invar','chord_histo','num_runs','pixel','pixel_invar','pixel_binary','gradient_8dir','cooc','moments_gray_plane'], 'greedy', 8, 10, ['nu','gamma'], ['auto','auto'], OCRHandle, FeatureSet, Score)
count_seconds (S2)
* Check the automatically estimated parameters
get_params_ocr_class_svm (OCRHandle, WidthCharacter, HeightCharacter, Interpolation, Features, CharactersT, KernelType, KernelParam, Nu, Mode, Preprocessing, NumComponents)
dev_clear_window ()
*自动参数估计…
*现在将在严重扭曲的字符上测试所有三个分类器,并计算错误率。
*您将看到,自动训练的分类器的性能接近手动优化的分类器。
Message[2] := ' \nAutomatic parameter estimation ... ' + (S2 - S1)$'6.1f' + 's'
disp_message (WindowHandle, Message, 'window', 12, 12, 'white', 'false')
String := 'Now all three classifiers will be tested'
String[1] := 'on heavily distorted characters and the'
String[2] := 'error rates are calculated.'
String[3] := ' \nYou will see, that the performance of the'
String[4] := 'automatically trained classifier is close'
String[5] := 'to the manually optimized one.'
disp_message (WindowHandle, String, 'window', 200, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()
* Now introduce heavy distortions into the characters
* and determine the error rates
NumDistort := 10
ErrorsSVMDef := 0
ErrorsSVMTuned := 0
ErrorsSVMAuto := 0
TimeSVMDef := 0
TimeSVMTun := 0
TimeSVMAut := 0
Num := 0
for J := 0 to NumChars - 1 by 1
select_obj (Characters, Char, J + 1)
Class := CharacterNames[J]
full_domain (Char, CharFull)
get_image_size (CharFull, Width, Height)
Num := max([J * NumDistort,1])
gen_empty_obj (Chars)
for K := 1 to NumDistort by 1
*生成扭曲变形的字符
gen_distorted_character (CharFull, CharDistort, 7)
full_domain (CharDistort, CharDistortFull)
threshold (CharDistortFull, Region, 0, 128)
reduce_domain (CharDistortFull, Region, CharSeg)
area_center (Region, Area, Row, Column)
if (Area < 2)
concat_obj (Chars, CharDistortFull, Chars)
else
concat_obj (Chars, CharSeg, Chars)
endif
dev_set_part (-Height, -Width, Height - 1 + Height, Width - 1 + Width)
dev_display (CharDistortFull)
dev_set_part (0, 0, 499, 499)
Message := 'Testing character ' + (J + 1) + ' of ' + NumChars
*错误率
Message[1] := 'Error rates for:'
*缺省设置的svm
Message[2] := 'Default: ' + (real(ErrorsSVMDef) / Num * 100)$'5.3f' + '%'
*人工优化设置的svm
Message[3] := 'Manually tuned SVM: ' + (real(ErrorsSVMTuned) / Num * 100)$'5.3f' + '%'
*自动特征选择的svm
Message[4] := 'Automatically tuned SVM: ' + (real(ErrorsSVMAuto) / Num * 100)$'5.3f' + '%'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
endfor
count_seconds (S1)
for K := 1 to NumDistort by 1
select_obj (Chars, CharDistort, K)
do_ocr_single_class_svm (CharDistort, CharDistort, OCRHandleSVMDefault, 1, ClassRes)
if (ClassRes != Class)
ErrorsSVMDef := ErrorsSVMDef + 1
endif
endfor
count_seconds (S2)
TimeSVMDef := TimeSVMDef + S2 - S1
count_seconds (S1)
for K := 1 to NumDistort by 1
select_obj (Chars, CharDistort, K)
do_ocr_single_class_svm (CharDistort, CharDistort, OCRHandleSVMOpt, 1, ClassRes)
if (ClassRes != Class)
ErrorsSVMTuned := ErrorsSVMTuned + 1
endif
endfor
count_seconds (S2)
TimeSVMTun := TimeSVMTun + S2 - S1
count_seconds (S1)
for K := 1 to NumDistort by 1
select_obj (Chars, CharDistort, K)
do_ocr_single_class_svm (CharDistort, CharDistort, OCRHandle, 1, ClassRes)
if (ClassRes != Class)
ErrorsSVMAuto := ErrorsSVMAuto + 1
endif
endfor
count_seconds (S2)
TimeSVMAut := TimeSVMAut + S2 - S1
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_set_check ('~give_error')
delete_file (TrainFile)
delete_file (TrainFileBig)
dev_set_check ('give_error')
dev_clear_window ()
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_message (WindowHandle, 'End of program', 'window', 150, 12, 'black', 'true')
*gen_initial_trainfile的源码:

read_image (Image, 'letters')
* Segment the image.
binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)
* Connect the i's and j's with their dots.
dilation_circle (Region, RegionDilation, 3.5)
* Compute the correct connected components.
connection (RegionDilation, ConnectedRegions)
* Reduce each connected component (character) to its original shape.
intersection (ConnectedRegions, Region, RegionIntersection)
* Sort the characters line-by-line.
sort_region (RegionIntersection, Characters, 'character', 'true', 'row')
* Compute the true class of each character.
count_obj (Characters, Number)
Classes := []
Sequence := [0:26 * 20 - 1]
Sequence := Sequence / 20
LetterColumn := chr(ord('a') + Sequence)
Classes := [LetterColumn,gen_tuple_const(20,'.')]
* Construct the necessary training file from the segmented characters.
write_ocr_trainf (Characters, Image, Classes, TrainFileName)
return ()gen_distorted_character函数源码:
它用于产生扭曲变形的字符。这个功能还是蛮有参考价值的!

get_image_size (Char, Width, Height) EroDil := rand(1) * NoiseLevel - (NoiseLevel / 2.0) if (EroDil < 0) gray_erosion_shape (Char, CharEroDil, 1 - EroDil, 1 - EroDil, 'rhombus') else gray_dilation_shape (Char, CharEroDil, 1 + EroDil, 1 + EroDil, 'rhombus') endif hom_mat2d_identity (HomMat2DIdentity) hom_mat2d_rotate (HomMat2DIdentity, rad(rand(1) * (NoiseLevel * 3.0) - ((NoiseLevel * 3.0) / 2.0)), Height / 2, Width / 2, HomMat2DRotate) hom_mat2d_translate (HomMat2DRotate, rand(1) * (NoiseLevel / 2.0) - (NoiseLevel / 4.0), rand(1) * (NoiseLevel / 2.0) - (NoiseLevel / 4.0), HomMat2DTranslate) affine_trans_image (CharEroDil, CharTrans, HomMat2DTranslate, 'constant', 'false') expand_domain_gray (CharTrans, CharExpanded, 2) gen_image_proto (CharExpanded, ImageBlank, 128) add_noise_white (ImageBlank, ImageNoise, 60) smooth_image (ImageNoise, ImageSmooth, 'gauss', 1) scale_image (ImageSmooth, ImageScaled, 3, -256) add_image (CharExpanded, ImageScaled, CharDistort, 1, -128) threshold (CharDistort, Region, 0, 128) reduce_domain (CharDistort, Region, CharDistort) return ()
相当精彩的演示程序,赞美一下!!
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路

















