Halcon实现颜色分类识别

183 阅读6分钟
  • 摘要

    • 本文主要描述并示例演示了如何使用Halcon实现的欧几里得分类(Euclidian classification),进行颜色识别在彩色图像上展示分类器的训练和应用实现颜色分类功能。案例中创建了对红、蓝、绿三种颜色进行分类识别。

  • 前言

    • (一)初始化设置

      • 创建新的显示窗口并设置字体、颜色等参数加载指定目录下的图像文件(支持多种格式如.jpg、.png等)
    • (二)训练

      • 通过绘制矩形框手动标注训练区域(红、蓝、绿、背景四类);
      • 使用learn_ndim_norm函数学习欧几里得距离模型,生成每个颜色类别的聚类信息(半径、中心点、质量);
      • 对背景区域单独处理,用于排除干扰。
    • (三)测试

      • 使用训练好的模型对每张图像进行测试;
      • 调用class_ndim_norm分类器检测颜色区域;
      • 通过连通区域分析和面积过滤(400-99999像素)去除噪点;
      • 统计并显示每类颜色的区域数量,标注检测结果(OK/NG)。
    • (四)结果显示

      • 用不同颜色高亮显示检测到的区域(金色-红、洋红-蓝、青色-绿)在窗口输出分类结果(颜色名称 + 数量),并标记是否通过检测。
    • (五)关键参数

      • 距离类型:'euclid'(欧几里得距离)。
      • 分类模式:'multiple'(允许一个区域属于多个类别)。
      • 面积阈值:400-99999像素,过滤无效区域。
      • 聚类上限:每类最多40个聚类(通过learn_ndim_norm的参数控制)。

  • 运行环境

    • 操作系统:Window 11
    • Halcon:HALCON 20.11

  • 一、预览

    • 运行效果1

    image.png

    • 运行效果2

    image.png

    • 运行效果3

    image.png


  • 二、代码

    * 这个示例演示了如何使用欧几里得分类(Euclidian classification)对进行颜色识别
    * 在彩色图像上展示分类器的训练和应用
    * 关闭程序更新,避免频繁刷新导致性能下降
    dev_update_off ()
    * 关闭所有图形窗口
    dev_close_window ()
    * 打开一个新的图形窗口,位置(0,0),大小557x416,背景黑色
    dev_open_window (0, 0, 557, 416, 'black', WindowHandle)
    * 设置显示字体:14号,等宽字体
    set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
    * 设置默认显示颜色为黑色
    dev_set_color ('black')
    * 设置绘图模式为边缘模式(只绘制区域边缘)
    dev_set_draw ('margin')
    * 图像目录
    ImageRootName := 'E:/Code/HalconDemo/颜色识别/color'
    **加载图像文件
    list_files(ImageRootName, ['files', 'follow_links'], ImageFiles)
    ** 筛选文件
    tuple_regexp_select(ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$', 'ignore_case'], ImageFiles)
    * 定义四个分类区域:红色、蓝色、绿色和背景色
    Regions := ['红色','蓝色','绿色','背景色']
    * 定义高亮显示颜色:显示匹配轮廓
    Highlight := ['goldenrod','magenta','cyan']
    * 创建一个空对象用于存储分类区域
    gen_empty_obj (Classes)
    * 处理图像:读取第一张图像用于训练
    read_image (Image, ImageFiles[0])
    * 彩色图像处理:为每个颜色类别指定训练区域
    for I := 1 to 4 by 1
        * 显示图像和已选择的区域
        dev_display (Image)
        dev_display (Classes)
        * 提示用户在指定颜色区域绘制矩形
        disp_message (WindowHandle, ['在【 ' + Regions[I - 1] + '】色区域内绘制矩形,鼠标右键按下确认'], 'window', 12, 12, 'black', 'false')
        * 让用户绘制矩形区域
        draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
        * 根据用户输入生成矩形区域
        gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
        * 将矩形区域添加到分类集合中
        concat_obj (Classes, Rectangle, Classes)    
    endfor
    * 训练欧几里得分类器
    disp_message (WindowHandle, '训练中...', 'window', 36, 12, 'black', 'false')
    * 初始化半径、中心和质量数组
    Radius := []
    Center := []
    Quality := []
    * 选择背景区域(第4个区域)
    select_obj (Classes, Background, 4)
    * 生成空背景区域
    gen_empty_region (Background)
    Circles := []
    * 为每个颜色类别生成分类簇
    for Class := 1 to |Regions|-1  by 1
        * 选择当前类别的训练区域
        select_obj (Classes, TrainClass, Class)
        * 学习正态分布模型(欧几里得距离)
        * 参数说明:训练区域、背景区域、图像、距离类型、最大聚类数、最小点数
        learn_ndim_norm (TrainClass, Background, Image, 'euclid', 40, 0, Rad, Cen, Qua)
        * 记录每个类别的聚类信息
        * 记录每个类别的聚类数量
        Circles := [Circles,|Rad|] 
        * 记录半径
        Radius := [Radius,Rad] 
        * 记录中心点
        Center := [Center,Cen]     
    endfor
    
    * 保存原始训练结果用于后续测试
    RadiusDup := Radius
    CenterDup := Center
    
    * 使用训练好的欧几里得分类器测试每张图像
    for J := 0 to |ImageFiles|-1 by 1
        * 恢复原始训练数据
        Radius := RadiusDup
        Center := CenterDup
        * 读取测试图像
        read_image (Image, ImageFiles[J])
        dev_display (Image)
        * 显示检测信息
        disp_message (WindowHandle, '寻找颜色数量...', 'window', 24, 12, 'black', 'false')
        * 对每个颜色类别进行分类检测
        for Class := 1 to |Regions|-1 by 1
            * 设置当前类别的高亮颜色
            dev_set_color (Highlight[Class - 1])
            * 应用欧几里得分类器进行分类
            * 参数说明:图像、输出区域、距离类型、模式、半径数组、中心点数组
            class_ndim_norm (Image, ClassRegions, 'euclid', 'multiple', Radius[0:Circles[Class - 1] - 1] + 30, Center[0:Circles[Class - 1] * 3 - 1])
            * 进行连通区域分析
            connection (ClassRegions, ConnectedRegions)
            * 选择面积在40099999之间的区域(过滤掉小噪点)
            select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 400, 99999)
            * 计算符合条件的区域数量
            count_obj (SelectedRegions, Number)
            * 更新半径和中心点数组(为下一个类别准备)
            if (Class < 3)
                Radius := Radius[Circles[Class - 1]:|Radius| - 1]
                Center := Center[Circles[Class - 1] * 3:|Center| - 1]
            endif
            * 显示检测到的区域
            dev_display (SelectedRegions)
            dev_set_color ('black')
            * 生成输出字符串:颜色名称+数量
            OutString := Regions[Class - 1] + ': ' + Number
            dev_set_color ('green')
            * 显示检测结果
            disp_message (WindowHandle, Regions[Class - 1] + ': ' + Number, 'window', 24 + 30 * Class, 12, 'black', 'false')
            * 检查数量是否足够(至少1个)
            if (Number <1)
                disp_message (WindowHandle, 'NG', 'window', 24 + 30 * Class, 120, 'red', 'false')
            else
                disp_message (WindowHandle, 'OK', 'window', 24 + 30 * Class, 120, 'green', 'false')
            endif
        endfor 
            * 设置线宽并暂停等待用户确认
            dev_set_line_width (2)
            disp_continue_message (WindowHandle, 'black', 'true')
            stop ()
    endfor
    

  • 结语

    • 本文主要是学习使用Halcon实现颜色分类识别功能,案例来源于官方,删减了一些。

  • 最后

    • 如果你觉得这篇文章对你有帮助,不妨点个赞再走呗!

    • 如有其他疑问,欢迎评论区留言讨论!

    • 也可以关注微信公众号 [编程笔记in] ,一起交流学习!