勇哥的视觉实验:K-NN分类器(二) 检测瓶口缺陷,演示了算子select_feature_set_knn用法

前言:

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

分类器相对于深度学习来讲是一种古老传统的图片处理技术。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%被占用。
分类器相对于深度学习来讲不吃硬件,所以相对来讲算是轻量级的应用。

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


这个瓶口检测的示例演示了算子select_feature_set_knn的用法和 *class_train_data的功能。

本例子是检查瓶颈是否有缺陷。

程序基于一组训练图像,选择一组参数集,对缺陷进行最佳判别。



引入“profile”和“profile_change”特性:我们希望自动估计控制极坐标变换分辨率的参数

image.png


第3部分:自动选择特征

使用knn分类器选择最佳特征

select_feature_set_knn算子不仅返回最佳功能,还有一个用这些训练出来的分类器。

image.png


最后进行好坏分类。

下图为OK品

image.png


大缺陷

image.png


小缺陷

image.png


NG,瓶口特征缺少

image.png


read_image (Image, 'bottles/bottle_mouth_01')
dev_update_off ()
dev_close_window ()
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, 640, 512, WindowHandle)
dev_open_window (0, 650, 448, 160, 'black', WindowHandleFeature)
dev_open_window (220, 650, 448, 512 - 220, 'black', WindowHandlePolar)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
set_display_font (WindowHandleFeature, 14, 'mono', 'true', 'false')
set_display_font (WindowHandlePolar, 14, 'mono', 'true', 'false')
dev_set_window (WindowHandle)
dev_display (Image)
*引入“profile”和“profile_change”特性:我们希望自动估计控制极坐标变换分辨率的参数。
disp_message (WindowHandle, 'Introducing the features "profile" and\n"profile_change":\nWe want to estimate automatically a parameter\nthat controls the resolution of a polar\ntransformation.', 'window', 12, 12, 'black', 'true')
dev_set_draw ('margin')
dev_set_line_width (3)
RingSize := 70

*第一部分:导言
*使用第一张图片解释特征
find_bottle_mouth (Image, Row, Column, Radius)
gen_circle_contour_xld (OuterCircle, Row, Column, Radius, 0, 6.28318, 'positive', 1)
dev_set_color ('green')
dev_display (OuterCircle)

* 创建显示特征的图像(仅用于可视化)
gen_image_const (FeatureImage, 'float', 14, 80)
* 变量初始化
FeatureNames := []
FeatureLength := []
DataSample := []
MinParamValue := 20
MaxParamValue := 80
ParameterIncrement := 10
Change := true

* 创建数据向量并为所有子功能命名
for TestParameter := MinParamValue to MaxParamValue by ParameterIncrement

    * 用TestParameter作为极坐标变换分辨率的参数计算特征
    compute_gray_value_profile (Image, Row, Column, RingSize, Radius, TestParameter, GrayValueProfile, GrayValueProfileChange)
    
    * 收集结果
    FeatureNames := [FeatureNames,'profile_' + TestParameter + '(' + TestParameter + ')','profile_change_' + TestParameter + '(c' + TestParameter + ')']
    FeatureLength := [FeatureLength,|GrayValueProfile|,|GrayValueProfileChange|]
    DataSample := [DataSample,GrayValueProfile,GrayValueProfileChange]
    
    * 显示特征,首先是轮廓...
    disp_gray_profile (FeatureImage, Image, PolarTransImage, GrayValueProfile, TestParameter, MinParamValue, ParameterIncrement, Row, Column, RingSize, Radius, WindowHandlePolar, WindowHandleFeature, Change, Columns, Rows, I)
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
    
    * ...然后显示更改的配置文件
    disp_gray_profile_change (FeatureImage, PolarTransImage, EdgeAmplitude, GrayValueProfileChange, TestParameter, MinParamValue, ParameterIncrement, WindowHandlePolar, WindowHandleFeature, WindowHandle, Columns, Rows, I)
    stop ()
endfor
dev_set_window (WindowHandlePolar)
dev_close_window ()


*第2部分:预训练
*为所有图像生成整个特征集
*为分类器创建训练数据结构
create_class_train_data (|DataSample|, ClassTrainDataHandle)
set_feature_lengths_class_train_data (ClassTrainDataHandle, FeatureLength, FeatureNames)

* 准备分类
ClassNames := ['perfect','small defect','large defect','completely missing']

* 
* 训练
* 
* 训练数据的类
ClassNumber := [0,2,1,1,2,1,3,0,2,1,1,2,2,2,2,1]

* 计算所有图像的特征
for Index := 1 to 16 by 1
    read_image (Image, 'bottles/bottle_mouth_' + Index$'.02')
    gen_circle_contour_xld (OuterCircle, Row, Column, Radius, 0, 6.28318, 'positive', 1)
    find_bottle_mouth (Image, Row, Column, Radius)
    DataSample := []
    ShortDescription := []
    
    * 计算整个特征集
    for TestParameter := MinParamValue to MaxParamValue by ParameterIncrement
        compute_gray_value_profile (Image, Row, Column, RingSize, Radius, TestParameter, GrayValueProfile, GrayValueProfileChange)
        DataSample := [DataSample,GrayValueProfile,GrayValueProfileChange]
        set_visualization_data (FeatureImage, GrayValueProfile, TestParameter, MinParamValue, ParameterIncrement, GrayValueProfileChange, Columns, Rows)
    endfor
    
    * 显示特征
    show_all_features (Image, FeatureImage, WindowHandle, ClassNames, ClassNumber, Index, WindowHandleFeature, MinParamValue, MaxParamValue, ParameterIncrement, TestParameter)
    if (Index < 16)
        disp_message (WindowHandleFeature, 'Features for image ' + Index, 'window', 120, 12, 'black', 'true')
    endif
    dev_display (OuterCircle)
    
    * 将特征向量添加到训练数据中
    add_sample_class_train_data (ClassTrainDataHandle, 'row', DataSample, number(ClassNumber[Index - 1]))
    wait_seconds (0.1)
endfor
dev_set_window (WindowHandle)

*
*第3部分:自动选择特征
*
*使用knn分类器选择最佳特征
*select_feature_set_knn算子不仅返回最佳功能,还有一个用这些训练出来的分类器。
select_feature_set_knn (ClassTrainDataHandle, 'greedy', [], [], KNNHandle, SelectedFeatureNames, Score)

dev_display (Image)
Message := 'Selected features:'
Message := [Message,' - ' + SelectedFeatureNames]
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
dev_set_window (WindowHandleFeature)
tuple_regexp_match (SelectedFeatureNames, '\\d+', Matches)
Sizes := number(Matches)
tuple_regexp_match (SelectedFeatureNames, '(c)\\d+', Matches)
Derivative := Matches [==] 'c'
gen_rectangle1 (Rectangle, gen_tuple_const(|Sizes|,0), (Sizes - 20) / 5 + Derivative, Sizes, (Sizes - 20) / 5 + Derivative)
dev_set_color ('green')
dev_set_draw ('margin')
dev_display (Rectangle)
disp_message (WindowHandleFeature, 'Selected best features', 'window', 120, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_set_window (WindowHandleFeature)
dev_close_window ()


* 将新训练的Classifier应用到训练集 
for Index := 1 to 16 by 1
    dev_set_window (WindowHandle)
    read_image (Image, 'bottles/bottle_mouth_' + Index$'.02')
    find_bottle_mouth (Image, Row, Column, Radius)
    Feature := []
    for IndexInner := 0 to |SelectedFeatureNames| - 1 by 1
        compute_gray_value_profile (Image, Row, Column, RingSize, Radius, Sizes[IndexInner], GrayValueProfile, GrayValueProfileChange)
        if (Derivative[IndexInner])
            Feature := [Feature,GrayValueProfileChange]
        else
            Feature := [Feature,GrayValueProfile]
        endif
    endfor
    
    * 分类
    classify_class_knn (KNNHandle, Feature, Result, Rating)
    dev_display (Image)
    gen_circle_contour_xld (OuterCircle, Row, Column, Radius, 0, 6.28318, 'positive', 1)
    if (ClassNames[Result] == 'completely missing')
        dev_set_color ('red')
    elseif (ClassNames[Result] == 'large defect')
        dev_set_color ('orange')
    elseif (ClassNames[Result] == 'small defect')
        dev_set_color ('yellow')
    else
        dev_set_color ('green')
    endif
    dev_display (OuterCircle)
    disp_message (WindowHandle, 'Image ' + Index + ': Classified as ' + ClassNames[Result], 'window', 12, 12, 'black', 'true')
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
endfor


compute_gray_value_profile函数

image.png

*此过程计算基于灰度值及其派生到一维特征数组的极坐标投影的特征。
*找到的圆被展开成极坐标图像
polar_trans_image_ext (Image, PolarTransImage, Row, Column, 0, rad(360), RingSize - 5, Radius + 5, ImageSize, ImageSize, 'bilinear')
* 投影灰度值
gray_projections (PolarTransImage, PolarTransImage, 'simple', GrayValueProfile, VertProjection2)
* 计算导数
sobel_amp (PolarTransImage, EdgeAmplitude, 'x_binomial', 3)
abs_image (EdgeAmplitude, ImageAbs)
* Project derivative
gray_projections (ImageAbs, ImageAbs, 'simple', GrayValueProfileChange, VertProjection1)
* 缩放导数到与图像值相似的缩放比例.
GrayValueProfileChange := GrayValueProfileChange * 5
return ()


disp_gray_profile函数代码:

image.png

* 显示灰度值配置文件
Columns := gen_tuple_const(|GrayValueProfile|,((TestParameter - MinParamValue) / ParameterIncrement) * 2)
Rows := [0:|GrayValueProfile| - 1]
set_grayval (FeatureImage, Rows, Columns, GrayValueProfile)
polar_trans_image_ext (Image, PolarTransImage, Row, Column, 0, rad(360), RingSize - 5, Radius + 5, TestParameter, TestParameter, 'bilinear')
dev_set_window (WindowHandlePolar)
dev_display (PolarTransImage)
Message := 'Polar transformation of the circle'
Message[1] := 'Resolution: ' + |GrayValueProfile| + ' pixels'
disp_message (WindowHandlePolar, Message, 'window', 12, 12, 'black', 'true')
dev_set_window (WindowHandleFeature)
dev_display (FeatureImage)
Message := 'Feature profile_' + TestParameter + ' (' + TestParameter + ')'
Message[1] := '(Projection of the transformation below)'
disp_message (WindowHandleFeature, Message, 'window', 110, 12, 'black', 'true')
for I := MinParamValue to TestParameter by ParameterIncrement
    disp_message (WindowHandleFeature, I, 'window', 1, 6 + 32 * (((I - MinParamValue) / ParameterIncrement) * 2), 'white', 'false')
    if (I < TestParameter)
        disp_message (WindowHandleFeature, 'c' + I, 'window', 1, 2 + 32 * (((I - MinParamValue) / ParameterIncrement) * 2 + 1), 'white', 'false')
    endif
endfor
return ()


disp_gray_profile_change函数

image.png

* 显示灰度导数特征
Columns := gen_tuple_const(|GrayValueProfileChange|,((TestParameter - MinParamValue) / ParameterIncrement) * 2 + 1)
Rows := [0:|GrayValueProfileChange| - 1]
set_grayval (FeatureImage, Rows, Columns, GrayValueProfileChange)
sobel_amp (PolarTransImage, EdgeAmplitude, 'x_binomial', 3)
dev_set_window (WindowHandlePolar)
dev_display (EdgeAmplitude)
Message := 'Sobel filtered polar transformation'
Message[1] := 'Resolution: ' + |GrayValueProfileChange| + ' pixels'
disp_message (WindowHandlePolar, Message, 'window', 12, 12, 'black', 'true')
dev_set_window (WindowHandleFeature)
dev_display (FeatureImage)
for I := MinParamValue to TestParameter by ParameterIncrement
    disp_message (WindowHandleFeature, I, 'window', 1, 6 + 32 * (((I - MinParamValue) / ParameterIncrement) * 2), 'white', 'false')
    disp_message (WindowHandleFeature, 'c' + I, 'window', 1, 2 + 32 * (((I - MinParamValue) / ParameterIncrement) * 2 + 1), 'white', 'false')
endfor
Message := 'Feature profile_change_' + TestParameter + ' (c' + TestParameter + ')'
Message[1] := '(Projection of the transformation below)'
disp_message (WindowHandleFeature, Message, 'window', 110, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
return ()


这个例子采用极坐标方式对瓶口进行缺陷收集,对极坐标图采用不同的分辨率(20-80像素)图像进行采集自适应用knn特征的方式,即决了定最佳分辨率,还直接返回用这些训练出来的knn分类器。

这个例子相当精彩,信息量很大,是缺陷检测的优秀示例。

勇哥分析记录这个例子的时候感觉文字图片乏力,还是觉得应该出一个视频教程才能说清楚。


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

作者: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