前言:
==========================================================
分类器相对于深度学习来讲是一种古老传统的图片处理技术。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%被占用。
分类器相对于深度学习来讲不吃硬件,所以相对来讲算是轻量级的应用。
==========================================================
这个例子程序比较了SVM和MLP OCR分类器的训练和识别时间。
首先,通过向字符添加合成变形(如移位、旋转和笔划宽度的变化),创建一个包含5000多个样本的中等规模的训练集。
包括偏移以模拟分割错误。当然,如果没有分割错误,OCR特征本身是平移不变的。
然后训练一个SVM分类器,对第一个SVM分类器进行reduce_ocr_class_svm,得到第二个SVM分类器。
(算子reduce_ocr_class_svm通过精简SVM得到近似的效果良好的基于SVM的OCR分类器)
最后训练MLP分类器。
你将看到,SVM和MLP分类器的训练在当前的多核计算机上大致相同。
最后,该程序通过对原始训练字符进行变形,并在训练字符中加入结构化噪声,生成测试字符。
您将看到SVM分类器比MLP分类器能够更好地处理这些特定类型的失真。
请注意,所选择的失真不一定反映实际应用中发生的失真。
您还将看到MLP分类器的分类时间更好。
训练一个svm, 一个经过reduce_ocr_class_svm后的svm,一个MLP。

以下为运行中抓取的某帧结果。最后给出了全部样本的的结果统计。
得到的SVM与MLP的对比结论如下:
SVM分类器比MLP分类器能够更好地处理这些特定类型的失真。
MLP分类器的分类时间更好



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')
get_tmp_dir (TmpDir)
TrainFile := TmpDir + '/letters.trf'
TrainFileBig := TmpDir + '/letters_big.trf'
* 创建原始训练样本并将其存储在训练文件中.
dev_clear_window ()
dev_set_part (0, 0, 499, 499)
disp_message (WindowHandle, 'Creating initial samples... ', 'window', 12, 12, 'green', 'false')
gen_initial_trainfile (TrainFile)
* 现在修改原始训练样本以创建更大的训练集.
disp_message (WindowHandle, 'Creating modified samples... ', 'window', 42, 12, 'green', 'false')
read_ocr_trainf_names (TrainFile, CharClasses, CharCount)
read_ocr_trainf (Characters, TrainFile, CharClassesSingle)
dev_set_check ('~give_error')
delete_file (TrainFileBig)
dev_set_check ('give_error')
count_obj (Characters, NumChars)
for J := 0 to NumChars - 1 by 1
select_obj (Characters, Char, J + 1)
Class := CharClassesSingle[J]
full_domain (Char, CharFull)
get_image_size (CharFull, Width, Height)
dev_set_part (0, 0, Height - 1, Width - 1)
append_ocr_trainf (CharFull, CharFull, Class, TrainFileBig)
append_ocr_translated (CharFull, 1, 1, TrainFileBig, Class)
append_ocr_translated (CharFull, 1, 0, TrainFileBig, Class)
append_ocr_translated (CharFull, 1, -1, TrainFileBig, Class)
append_ocr_translated (CharFull, 0, -1, TrainFileBig, Class)
append_ocr_translated (CharFull, -1, -1, TrainFileBig, Class)
append_ocr_translated (CharFull, -1, 0, TrainFileBig, Class)
append_ocr_translated (CharFull, -1, 1, TrainFileBig, Class)
append_ocr_translated (CharFull, 0, 1, TrainFileBig, Class)
append_ocr_rotated (CharFull, 3, TrainFileBig, Class)
append_ocr_rotated (CharFull, -3, TrainFileBig, Class)
append_ocr_rotated (CharFull, 5, TrainFileBig, Class)
append_ocr_rotated (CharFull, -5, TrainFileBig, Class)
append_ocr_rotated (CharFull, 8, TrainFileBig, Class)
append_ocr_rotated (CharFull, -8, TrainFileBig, Class)
append_ocr_erosion (CharFull, 1.2, TrainFileBig, Class)
append_ocr_erosion (CharFull, 1.5, TrainFileBig, Class)
append_ocr_dilated (CharFull, 1.2, TrainFileBig, Class)
append_ocr_dilated (CharFull, 1.5, TrainFileBig, Class)
endfor
* 训练SVM和MLP分类器。
*注:为简单起见,分类是在原始灰度值上进行的,而不分割字符。
*在实际的应用程序中,字符当然必须被分割。
*在这种情况下,区域特征也将用于分类。
dev_clear_window ()
dev_set_part (0, 0, 499, 499)
disp_message (WindowHandle, 'Training SVM... ', 'window', 20, 20, 'green', 'false')
create_ocr_class_svm (8, 10, 'constant', 'pixel_invar', CharClasses, 'rbf', 0.01, 0.01, 'one-versus-all', 'normalization', 10, OCRHandleSVM)
count_seconds (S1)
trainf_ocr_class_svm (OCRHandleSVM, TrainFileBig, 0.001, 'default')
count_seconds (S2)
disp_message (WindowHandle, 'Training SVM... ' + (S2 - S1)$'5.2f' + 's', 'window', 20, 20, 'green', 'false')
get_support_vector_num_ocr_class_svm (OCRHandleSVM, NumSupportVectors, NumSVPerSVM)
disp_message (WindowHandle, 'Reducing SVM... ', 'window', 50, 20, 'green', 'false')
count_seconds (S1)
* 请注意,在本例中,MaxError参数被设置为人为的大值。
*在实际应用中,必须根据独立测试数据集上的错误率来确定此参数
reduce_ocr_class_svm (OCRHandleSVM, 'bottom_up', 2, 0.1, OCRHandleSVMR)
count_seconds (S2)
disp_message (WindowHandle, 'Reducing SVM... ' + (S2 - S1)$'5.2f' + 's', 'window', 50, 20, 'green', 'false')
get_support_vector_num_ocr_class_svm (OCRHandleSVMR, NumSupportVectorsR, NumSVPerSVMR)
disp_message (WindowHandle, 'Training MLP... ', 'window', 80, 20, 'green', 'false')
create_ocr_class_mlp (8, 10, 'constant', 'pixel_invar', CharClasses, 50, 'none', 10, 42, OCRHandleMLP)
count_seconds (S1)
trainf_ocr_class_mlp (OCRHandleMLP, TrainFileBig, 200, 1, 0.01, Error, ErrorLog)
count_seconds (S2)
disp_message (WindowHandle, 'Training MLP... ' + (S2 - S1)$'5.2f' + 's', 'window', 80, 20, 'green', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 在在字符中引入严重失真,并确定错误率和分类时间.
NumDistort := 10
ErrorsSVM := 0
ErrorsSVMR := 0
ErrorsMLP := 0
TimeSVM := 0
TimeSVMR := 0
TimeMLP := 0
set_window_param (WindowHandle, 'flush', 'false')
for J := 0 to NumChars - 1 by 1
select_obj (Characters, Char, J + 1)
Class := CharClassesSingle[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)
concat_obj (Chars, CharDistort, Chars)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (CharDistort)
dev_set_part (0, 0, 499, 499)
disp_message (WindowHandle, 'SVM: Time: ' + (TimeSVM / Num * 1000)$'4.2f' + 'ms, Errors: ' + (real(ErrorsSVM) / Num * 100)$'5.3f' + '%', 'window', 20, 20, 'black', 'true')
disp_message (WindowHandle, 'Red. SVM: Time: ' + (TimeSVMR / Num * 1000)$'4.2f' + 'ms, Errors: ' + (real(ErrorsSVMR) / Num * 100)$'5.3f' + '%', 'window', 50, 20, 'black', 'true')
disp_message (WindowHandle, 'MLP: Time: ' + (TimeMLP / Num * 1000)$'4.2f' + 'ms, Errors: ' + (real(ErrorsMLP) / Num * 100)$'5.3f' + '%', 'window', 80, 20, 'black', 'true')
flush_buffer (WindowHandle)
endfor
count_seconds (S1)
for K := 1 to NumDistort by 1
select_obj (Chars, CharDistort, K)
do_ocr_single_class_svm (CharDistort, CharDistort, OCRHandleSVM, 1, ClassRes)
if (ClassRes != Class)
ErrorsSVM := ErrorsSVM + 1
endif
endfor
count_seconds (S2)
TimeSVM := TimeSVM + S2 - S1
count_seconds (S1)
for K := 1 to NumDistort by 1
select_obj (Chars, CharDistort, K)
do_ocr_single_class_svm (CharDistort, CharDistort, OCRHandleSVMR, 1, ClassRes)
if (ClassRes != Class)
ErrorsSVMR := ErrorsSVMR + 1
endif
endfor
count_seconds (S2)
TimeSVMR := TimeSVMR + S2 - S1
count_seconds (S1)
for K := 1 to NumDistort by 1
select_obj (Chars, CharDistort, K)
do_ocr_single_class_mlp (CharDistort, CharDistort, OCRHandleMLP, 1, ClassRes, Confidence)
if (ClassRes != Class)
ErrorsMLP := ErrorsMLP + 1
endif
endfor
count_seconds (S2)
TimeMLP := TimeMLP + S2 - S1
endfor
set_window_param (WindowHandle, 'flush', 'true')
dev_clear_window ()
dev_set_part (0, 0, 499, 499)
Num := NumChars * NumDistort
disp_message (WindowHandle, 'SVM: Time: ' + (TimeSVM / Num * 1000)$'4.2f' + 'ms, Errors: ' + (real(ErrorsSVM) / Num * 100)$'5.3f' + '%', 'window', 20, 20, 'green', 'false')
*即reduce_ocr_class_svm后的svm
disp_message (WindowHandle, 'Red. SVM: Time: ' + (TimeSVMR / Num * 1000)$'4.2f' + 'ms, Errors: ' + (real(ErrorsSVMR) / Num * 100)$'5.3f' + '%', 'window', 50, 20, 'green', 'false')
disp_message (WindowHandle, 'MLP: Time: ' + (TimeMLP / Num * 1000)$'4.2f' + 'ms, Errors: ' + (real(ErrorsMLP) / Num * 100)$'5.3f' + '%', 'window', 80, 20, 'green', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_set_check ('~give_error')
delete_file (TrainFile)
delete_file (TrainFileBig)
dev_set_check ('give_error')本例程是:compare_ocr_svm_mlp.hdev
比较svm和mlp的区别的例程比较少见,值得一读!
而在官方手册上提到svm与mlp的比较如下:
SVM和多层感知器(MLP)的比较: 通常情况下,SVM通常在训练时速度更快,尤其是对于大型训练集,其识别率比MLP略高。 MLP分类速度更快,因此在时间紧迫的应用中应首选。请注意,本指南假定参数的最佳调整。
当然,两者在原理上是完全不同的,以上仅是在使用效果上的对比。
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路


















