勇哥的视觉实验:SVM分类器(一) 支持向量机的应用例子,分类卤素灯泡的好坏

前言:

==========================================================

分类器相对于深度学习来讲是一种古老传统的图片处理技术。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张测试图片
训练最好不要用用于测试的图片会影响训练效果。测试同理 最好不要用训练图片 以免得到错误的结果。

image.png


OK品的图片如下:

image.png

ng品的图片如下:

image.png

人目检OKNG的差别主要在下图所示的地方:

image.png


源码:

* 该程序使用支持向量机分类器来检测坏的卤素灯泡。
*训练图像必须存储在以类名命名的子目录中。
*可以编辑“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函数代码:

image.png

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函数代码:

image.png

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函数代码:

image.png

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的特征向量:

image.png

ng2

image.png

ng3

image.png

ok1

image.png

ok2

image.png

通过观察:

三个region特征: 面积、紧密度、凸度 在特征提取中发挥了明显的作用。

image.png

那四个不变矩特征(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时三个参数的函数图形的变化。

image.pngimage.png

这四个不变矩称为:计算旋转线性移动不变矩_二阶矩

以上实验勇哥只是从应用角度看到现象,但是仍然不知道这个不变矩是什么鬼!

希望有懂这个的朋友给些浅显资料参考一下。非常感谢!


--------------------- 

作者:hackpig
来源:
www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!



本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864