当前位置: 首页 > 工具软件 > Citrus > 使用案例 >

Halcon例程(基于GMM模型的分类)详解 —— classify_citrus_fruits.hdev

澹台庆
2023-12-01

一、例程简介

该例程比较有代表性,属于Halcon里的分类方法之一,直接调用Halcon封装好的GMM分类器(高斯混合模型)对橘子和柠檬进行分类。GMM属于概率分类方法,属于P(Y|X),通过对样本的概率密度分布进行估计,然后对模型进行加权求和,并通过投影,最后选取概率最大的类所为判决结果,这种分类方法只在不同检测类之间有明显的区别(在两类物体圆度和面积有较大区别)的情况下适用。
具体原理可以详见有位大佬的解释说明,链接如下:
[原理]https://blog.csdn.net/weixin_42555080
后面我也会针对机器学习的相关方法进行分享,求点赞评论哦。

二、代码详解(对每一步进行注释)

第一篇注释下,后面再写就只注释关键部分了。

*读取图片
read_image (Image, 'color/citrus_fruits_01')
*返回输入图像对象Image的第一个通道的Pointer(指示器)。另外,这个算子也返回图像类型和图像的大小(width和height)。
get_image_pointer1 (Image, Pointer, Type, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'white', WindowHandle)
*用来设置当前窗口的字体属性,参数意思为字体大小为12,字体类型为“Courier New字体”,粗体,不倾斜。
set_display_font (WindowHandle, 12, 'mono', 'true', 'false')
* 定义region的填充模式, 如果参数DrawMode设置为'fill',region显示为填充,如果设置为'margin',则只显示轮廓。
dev_set_draw ('margin')
*设置线宽
dev_set_line_width (2)
*显示图片
dev_display (Image)
*其实以下几句可以写为一句dev_update_off ()
dev_update_window ('off')
dev_update_pc ('off')
dev_update_var ('off')
* 为特征量(区域的面积,圆度,和分类名)赋值
FeaturesArea := []
FeaturesCircularity := []
ClassName := ['orange','lemon']

* 创建GMM分类器(特征数量,样本分类个数,类中心的个数,协方差矩阵的形式,预处理的形式,转换特征数,随机种子初始化GMM,GMM句柄)
create_class_gmm (2, 2, 1, 'spherical', 'normalization', 10, 42, GMMHandle)
* 
* 添加训练样本
for I := 1 to 4 by 1
    read_image (Image, 'color/citrus_fruits_' + I$'.2d')
    dev_display (Image)
    * 自定义函数,将图片进行预处理,得到区域特征。
    get_regions (Image, SelectedRegions)
    *将彩色图片分离为三个单通道图片
    (decompose3 (Image, ImageRed, ImageGreen, ImageBlue)
    *用于区域对象的颜色设为白
    dev_set_color ('white')
    *对单通道图片进行阈值处理,得到灰度值在50-255区间的图片
    threshold (ImageRed, Region, 50, 255)
    *将区域进行填充
    fill_up (Region, RegionFillUp)
    *用来计算输入区域中的所有连通域
    connection (RegionFillUp, ConnectedRegions)
    *根据形状特征(这里是面积)对区域进行筛选,对于大于50小于999999的形状保留。
    select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 50, 999999)
    return ())
    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)
        (circularity (ObjectSelected, Circularity)
            area_center (ObjectSelected, Area, Row, Column)
            dev_set_color ('white')
            return ())
        * 对变量赋值
        FeaturesArea := [FeaturesArea,Area]
        FeaturesCircularity := [FeaturesCircularity,Circularity]
        *将元组的数值转换为浮点型
        FeatureVector := real([Circularity,Area])
        *该方法已提前将样本分为两类,每类数量已提前设定好,橘子和柠檬各两张图片
        if (I <= 2)
        *将训练样本添加到训练数据中(GMM句柄,特征向量,类别ID为0,不添加高斯噪声)
            add_sample_class_gmm (GMMHandle, FeatureVector, 0, 0)
       *此过程在图形窗口“窗口句柄”中的位置(Row,Column)显示文本。(文本显示Add to Class加类名,行坐标,列坐标,黑色,box参数为ture,表示文本显示在橙色框中)
            disp_message (WindowHandle, 'Add to Class:' + ClassName[0], 'window', RowRegionCenter, ColumnRegionCenter - 100, 'black', 'true')
        else
        *ID为1
            add_sample_class_gmm (GMMHandle, FeatureVector, 1, 0)
            disp_message (WindowHandle, 'Add to Class:' + ClassName[1], 'window', RowRegionCenter, ColumnRegionCenter - 100, 'black', 'true')
        endif
    endfor
    *显示 'Press Run (F5) to continue' 在屏幕的右下角
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
endfor
dev_clear_window ()
* 
* 自定义函数,构建可视化空间,可以显示圆度和面积的二维坐标系,里面内容有点复杂,包括画坐标系,显示特征值两部分,有兴趣的同学可以仔细看看里面的代码来复现一遍,这里就不细述。两个特征变量里面分别有12个值,对应每个对象的特征值,将其放到坐标系中,橘子为深灰,柠檬为浅灰色。
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 ()
* 
* 训练分类器(句柄,最大迭代次数,阈值,计算方法,防止协方差矩阵异常的正则化值,类中心数量,每个类的迭代次数)这里就是halcon的便利之处,直接将大量的代码封装,我们只需要更改几个关键参数即可,但也要对GMM训练算法有所了解,后面会专门写一篇GMM算法的文章。
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])
        *应用上面训练的模型对测试数据的特征进行分类(句柄,特征向量,最佳类数(我的理解是指返回一种结果),分类结果(橘子是0,柠檬是1),后验概率,概率密度,归一化概率(通过这个概率进行判断))
        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
    *如果测试图片数量不等于15,显示暂停。
    if (I != 15)
        disp_continue_message (WindowHandle, 'black', 'true')
    endif
    stop ()
endfor
* 清除分类器内存
clear_class_gmm (GMMHandle)

三、总结

Halcon进行GMM分类的全过程包括以下几部分:

  1. 预处理,包括阈值处理,二值化,提取区域或者轮廓特征等;
  2. 提取样本特征;可以是圆度,面积,也可以是颜色,轮廓,主要看那种特征适合分类。
  3. 用add_sample_class_gmm将样本特征添加到分类器,对特征进行训练,得到最终GMM模型。
  4. 提取测试样本的特征。
  5. 应用分类器对测试数据进行分类,这里Halcon把代码封装了,大家可以去看看C++或python版本的分类代码,会对这个分类方法有更深的了解,至于先验后验概率密度之类的东西,大家自己查下吧,哈哈,要慢慢理解。
    第一次写博客,希望将自己的学习过程记录下来,也分享给大家,希望共同进步。必须强调一点,一三连。
 类似资料: