前言:
==========================================================
分类器相对于深度学习来讲是一种古老传统的图片处理技术。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://www.skcircle.com/?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
版权声明:本文为博主原创文章,转载请附上博文链接!

