前言:
==========================================================
分类器相对于深度学习来讲是一种古老传统的图片处理技术。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%被占用。
分类器相对于深度学习来讲不吃硬件,所以相对来讲算是轻量级的应用。
==========================================================
GMM是高斯混合模形分类, 它是按贝叶斯决策规则进行工作的分类器。
GMM的一些特点如下:
GMM仅仅对于低维的特征向量是可行的(大约差不多15个特征), 因此HALCON仅仅用GMM来对一般特征进行分类和图像分割,而不是OCR。 典型的应用就是图像分割和异常检测。异常检测对于GMM是特殊的。 其意味着不属于训练类之一的特征向量将被拒绝。
我们先来解读一个官方的例子,它使用GMM识别两种不同的水果。

A
柠檬和桔子。
使用的特征是两者的Area和circularity,即region的属性“面积”和“圆度”
有关region的这些常见属性可以参考:http://47.98.154.65/?id=1617
源码:
从源码上来看,GMM的用法跟PLM基本方式是一致的。算子的名命套路也保持了一致。
PLM的代码稍加修改可以轻松改为GMM的。
read_image (Image, 'color/citrus_fruits_01')
get_image_pointer1 (Image, Pointer, Type, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'white', WindowHandle)
set_display_font (WindowHandle, 12, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (2)
dev_display (Image)
dev_update_window ('off')
dev_update_pc ('off')
dev_update_var ('off')
*
FeaturesArea := []
FeaturesCircularity := []
ClassName := ['orange','lemon']
*
create_class_gmm (2, 2, 1, 'spherical', 'normalization', 10, 42, GMMHandle)
*
* 增加训练样本,共四张图片,6个桔子,6个柠檬
for I := 1 to 4 by 1
read_image (Image, 'color/citrus_fruits_' + I$'.2d')
dev_display (Image)
* 'Add Samples'
get_regions (Image, SelectedRegions)
dev_display (SelectedRegions)
count_obj (SelectedRegions, NumberObjects)
for J := 1 to NumberObjects by 1
select_obj (SelectedRegions, ObjectSelected, J)
get_features (ObjectSelected, WindowHandle, Circularity, Area, RowRegionCenter, ColumnRegionCenter)
FeaturesArea := [FeaturesArea,Area]
FeaturesCircularity := [FeaturesCircularity,Circularity]
FeatureVector := real([Circularity,Area])
if (I <= 2)
add_sample_class_gmm (GMMHandle, FeatureVector, 0, 0)
disp_message (WindowHandle, 'Add to Class:' + ClassName[0], 'window', RowRegionCenter, ColumnRegionCenter - 100, 'black', 'true')
else
add_sample_class_gmm (GMMHandle, FeatureVector, 1, 0)
disp_message (WindowHandle, 'Add to Class:' + ClassName[1], 'window', RowRegionCenter, ColumnRegionCenter - 100, 'black', 'true')
endif
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
endfor
dev_clear_window ()
*
* 绘制特征图表
visualize_2D_feature_space (Cross, Height, Width, WindowHandle, FeaturesArea[0:5],\
FeaturesCircularity[0:5], 'dim gray', 18)
* 'oranges', 40, 440
visualize_2D_feature_space (Cross, Height, Width, WindowHandle, FeaturesArea[6:11],\
FeaturesCircularity[6:11], 'light gray', 18)
* 'lemons', 70, 440
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 训练
train_class_gmm (GMMHandle, 100, 0.001, 'training', 0.0001, Centers, Iter)
for I := 1 to 15 by 1
read_image (Image, 'color/citrus_fruits_' + I$'.2d')
dev_display (Image)
* 'Classify Image', 10, 10
get_regions (Image, SelectedRegions)
dev_display (SelectedRegions)
count_obj (SelectedRegions, NumberObjects)
for J := 1 to NumberObjects by 1
select_obj (SelectedRegions, ObjectSelected, J)
get_features (ObjectSelected, WindowHandle, Circularity, Area, RowRegionCenter, ColumnRegionCenter)
FeaturesArea := [FeaturesArea,Area]
FeaturesCircularity := [FeaturesCircularity,Circularity]
FeatureVector := real([Circularity,Area])
classify_class_gmm (GMMHandle, FeatureVector, 1, ClassID, ClassProb, Density, KSigmaProb)
disp_message (WindowHandle, 'Class: ' + ClassName[ClassID], 'window', RowRegionCenter, ColumnRegionCenter - 100, 'black', 'true')
disp_message (WindowHandle, 'KSigmaProb: ' + KSigmaProb, 'window', RowRegionCenter + 30, ColumnRegionCenter - 100, 'black', 'true')
endfor
if (I != 15)
disp_continue_message (WindowHandle, 'black', 'true')
endif
stop ()
endfor
clear_class_gmm (GMMHandle)函数visualize_2D_feature_space代码如下:

*
* Create a coordinate system and draw its axes:
dev_set_color ('black')
OriginOfGraph := [Height - 0.1 * Height,0.1 * Width]
disp_arrow (WindowID, OriginOfGraph[0], OriginOfGraph[1], OriginOfGraph[0], Width - 0.2 * Width, 2)
disp_arrow (WindowID, OriginOfGraph[0], OriginOfGraph[1], 0.1 * Height, OriginOfGraph[1], 2)
set_tposition (WindowID, OriginOfGraph[0], Width - 0.2 * Width)
write_string (WindowID, 'Area')
set_tposition (WindowID, 0.07 * Height, OriginOfGraph[1])
write_string (WindowID, 'Circularity')
dev_set_color (ColorFeatureVector)
*
* Define the extent of the graph in image coordinates, the
* approximated ranges between the minimum and maximum
* feature values, and calculate the resulting
* scale factor for each feature axis:
ExtentOfGraph := Height - 0.3 * Height
RangeC := 0.5
RangeA := 24000
ScaleC := ExtentOfGraph / RangeC
ScaleA := ExtentOfGraph / RangeA
*
* Set the approximated minimum values of the features, which
* are the feature values at the origin of the graph:
MinC := 0.5
MinA := 20000
*
* Get the individual feature vectors in image coordinates
* and visualize them:
NumberFeatureVectors := |FeaturesA|
for I := 0 to NumberFeatureVectors - 1 by 1
*
* Get the distance of the feature i from
* the origin of the graph in pixels:
DiffC := ScaleC * (FeaturesC[I] - MinC)
DiffA := ScaleA * (FeaturesA[I] - MinA)
*
* Get the row and column of the feature
* vector in image coordinates:
RowFeature := OriginOfGraph[0] - DiffC
ColumnFeature := OriginOfGraph[1] + DiffA
*
* Generate a cross contour for the feature vector i:
gen_cross_contour_xld (Cross, RowFeature, ColumnFeature, CrossSize, 0.785398)
dev_display (Cross)
endfor
return ()代码中visualize_2D_feature_space函数用来绘制特征值的图表,它很形象的表示出分类的效果。
下面这段代码是第0到第5个特征的分布图,它是6个桔子的特征,使用灰度的点表示。
visualize_2D_feature_space (Cross, Height, Width, WindowHandle, FeaturesArea[0:5],\ FeaturesCircularity[0:5], 'dim gray', 18)

下面的代码显示的是第6到11个特征分布图,它是6个柠檬的特征,用淡灰色点表示。
visualize_2D_feature_space (Cross, Height, Width, WindowHandle, FeaturesArea[6:11],\ FeaturesCircularity[6:11], 'light gray', 18)
从这张图我们看到,灰色的6个点应该是桔子的特征点,因为桔子比柠檬更圆。
下面的6个浅灰色的点是柠檬的,它的面积和圆度都比桔子要小。
中间有一个浅灰的点意味着有一个柠檬,它的面积是所有柠檬中最大的,而且最圆。
左上那个灰色的点,表示有一个桔子是所有桔子中面积最小的,而且最不圆的。

我把四张训练图截出来,看看是不是勇哥分析的那样。
第一张图:

第二张:

第三张:

第四张:

从上面的特征分布图上看,灰色与浅色的特征被拉得越开越好,这样分类就会稳定可靠。
中间那个浅灰的点的特征则稍有不佳,如果再靠上一点,则可能分类到桔子类别上去了。
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路


















