前言:
==========================================================
分类器相对于深度学习来讲是一种古老传统的图片处理技术。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%被占用。
分类器相对于深度学习来讲不吃硬件,所以相对来讲算是轻量级的应用。
==========================================================
训练图片分为三类 good, bad, none
另有8张测试图片
训练最好不要用用于测试的图片会影响训练效果。测试同理 最好不要用训练图片 以免得到错误的结果。
OK品的图片如下:
ng品的图片如下:
人目检OKNG的差别主要在下图所示的地方:
源码:
* 该程序使用支持向量机分类器来检测坏的卤素灯泡。 *训练图像必须存储在以类名命名的子目录中。 *可以编辑“calculate_features”程序,为分类选择不同的特征(如果特征数量改变, *您还必须更改create_class_svm的第一个参数) * get_system ('image_dir', HalconImages) get_system ('operating_system', OS) if (OS{0:2} == 'Win') tuple_split (HalconImages, ';', HalconImages) else tuple_split (HalconImages, ':', HalconImages) endif ReadOK := false 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', 12, 12, 'black', 'true') stop () endif 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, 'mono', 'true', 'false') * ClassNames := ['good','bad','none'] Colors := ['forest green','red','red'] Nu := 0.05 KernelParam := 0.02 * * 创建SVM create_class_svm (7, 'rbf', KernelParam, Nu, |ClassNames|, 'one-versus-one',\ 'principal_components', 5, SVMHandle) * * 添加样本 add_samples_to_svm (ClassNames, SVMHandle, WindowHandle, ReadPath) dev_clear_window () * * 训练 disp_message (WindowHandle, 'Training...', 'window', 12, 12, 'black', 'true') train_class_svm (SVMHandle, 0.001, 'default') disp_message (WindowHandle, 'Training completed', 'window', 12, 12, 'black', 'true') disp_continue_message (WindowHandle, 'black', 'true') stop () * * 分类 classify_regions_with_svm (SVMHandle, Colors, ClassNames, ReadPath) * * Clear the classifier from memory clear_class_svm (SVMHandle)
add_samples_to_svm函数代码:
for ClassNumber := 0 to |ClassNames| - 1 by 1 list_files (ReadPath + ClassNames[ClassNumber], 'files', Files) Selection := regexp_select(Files,'.*[.]png') for Index := 0 to |Selection| - 1 by 1 read_image (Image, Selection[Index]) dev_display (Image) * 'Add Samples...', -1 threshold (Image, Region, 0, 40) calculate_features (Region, Features) add_sample_class_svm (SVMHandle, Features, ClassNumber) endfor endfor return ()
在这个函数里,
ClassNames的值是:['good', 'bad', 'none']
因此add_sample_class_svm (SVMHandle, Features, ClassNumber) 会依次从good、bad、none目录读取对应的图片进行训练。
三个分类的序号ClassNumber是:0,1,2
classify_regions_with_svm函数代码:
list_files (ReadPath, ['files','recursive'], Files) Selection := regexp_select(Files,'.*[.]png') read_image (Image, Selection[0]) dev_close_window () get_image_size (Image, Width, Height) dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowHandle) set_display_font (WindowHandle, 14, 'mono', 'true', 'false') for Index := 0 to |Selection| - 1 by 1 read_image (Image, Selection[Index]) threshold (Image, Region, 0, 40) calculate_features (Region, Features) classify_class_svm (SVMHandle, Features, 1, Class) dev_display (Image) dev_set_color (Colors[Class]) dev_display (Region) disp_message (WindowHandle, 'Classified as:' + ClassNames[Class],\ 'window', 12, 12, 'black', 'true') disp_continue_message (WindowHandle, 'black', 'true') stop () endfor dev_display (Image) return ()
calculate_features函数代码:
area_center (Region, Area, Row, Column) compactness (Region, Compactness) moments_region_central_invar (Region, PSI1, PSI2, PSI3, PSI4) convexity (Region, Convexity) Features := real([Area,Compactness,PSI1,PSI2,PSI3,PSI4,Convexity]) return ()
这个函数由传入的区域计算区域特征:
面积(Area)
密实度(Compactness)
四个不变矩特征(PSI1,PSI2,PSI3,PSI4)
凸度(Convexity)
以上region的特征详细可参考:http://www.skcircle.com/?id=1617
我们重点看下calculate_features函数提取的特征的效果,这个是关键:
ng1的特征向量:
ng2
ng3
ok1
ok2
通过观察:
三个region特征: 面积、紧密度、凸度 在特征提取中发挥了明显的作用。
那四个不变矩特征(PSI1,PSI2,PSI3,PSI4)数据暂时不明白意义。
勇哥把calculate_features函数修改了一下,取消了四个不变矩。
*Features := real([Area,Compactness,PSI1,PSI2,PSI3,PSI4,Convexity]) Features := real([Area,Compactness,Convexity])
然后改下create_class_svm函数参数:
create_class_svm (3, 'rbf', KernelParam, Nu, |ClassNames|, 'one-versus-one',\ 'principal_components', 3, SVMHandle)
结果在第13、15张识别错误,ng误判为ok。
这说明四个不变矩是有意义的。
勇哥监视了一下四个矩的PSI1的值,发现它在ok,ng物料时区别不大。
而PSI2,PSI3,PSI4反而区别比较大,因此专用监视这三个参数,下面两张图是NG、OK时三个参数的函数图形的变化。
这四个不变矩称为:计算旋转线性移动不变矩_二阶矩
以上实验勇哥只是从应用角度看到现象,但是仍然不知道这个不变矩是什么鬼!
希望有懂这个的朋友给些浅显资料参考一下。非常感谢!
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!