Halcon学习(7):颜色识别

先说一下RGB和HSV这两种颜色空间。大部分人可能接触RGB这种颜色空间多一些,相较于人这种颜色空间对硬件更加友好;而HSV更符合人的视觉感观,对人友好,如果你是画家、设计师,接触的可能会多一些。H是色调,表示是哪种颜色,取值是0到360度,比如0表示是红色;S表示是饱和度,取值0%到100%,越鲜艳值就越高,颜色越淡值越小;V表示亮度,取值0%到100%,越白值越大,越暗值越小。

1.第一种思路:利用HSV不同分量具有不同特点

下面的一个例子展示的是在不同颜色的线中分割出黄色的线。其大致思路是,先转到HSV空间,由于是白底,电线的颜色又比较鲜艳,可以用S分量做粗分割,得到颜色比较鲜艳区域;再后利用黄色的H分量在40左右进行精分割,最后做一些其他处理得到最终的结果。代码如下:(可以在例程的 应用范围->颜色检测->color_simple.hdev 找到)

* color_simple.hdev: segment yellow cable in HSV color space
dev_close_window ()
dev_open_window (0, 0, 640, 480, 'black', WindowHandle)
for i := 1 to 2 by 1
    read_image (Image, 'cable' + i)
    decompose3 (Image, Red, Green, Blue)
    trans_from_rgb (Red, Green, Blue, Hue, Saturation, Intensity, 'hsv')
    threshold (Saturation, HighSaturation, 100, 255)
    reduce_domain (Hue, HighSaturation, HueHighSaturation)
    threshold (HueHighSaturation, Yellow, 20, 50)
    connection (Yellow, ConnectedRegions)
    *选择面积最大那个区域
    select_shape_std (ConnectedRegions, SelectedRegions, 'max_area', 0)
    *闭运算:先膨胀后腐蚀
    closing_circle (SelectedRegions, Yellow, 3.5)
    reduce_domain (Image, Yellow, ImageReduced)
    dev_display (HueHighSaturation)
    dev_display (ImageReduced)
    stop ()
endfor

下面的例子和上面那个大体思路是相同的,不过处理的更加细致。下面的例子的主要目标是通过颜色对熔断器(fuse)进行分类并统计个数(不同颜色的熔断器具有不同属性,这个属性是允许通过最大的电流)。代码如下:(可以在例程的 应用范围->颜色检测->color_fuses_lut_trans.hdev 找到)

* color_fuses_lut_trans.hdev: classify fuses by color
dev_update_off ()
* ****
* step: 设置熔断器不同颜色具有允许通过最大的电流,以及不同颜色的色调区间
* ****
FuseColors := ['Orange','Red','Blue','Yellow','Green']
DisplayColors := ['coral','red','blue','goldenrod','forest green']
FuseTypes := [5,10,15,20,30]
* HueRanges: Orange 10-30, Red 0-10...
HueRanges := [10,30,0,10,125,162,30,64,96,128]
dev_close_window ()
read_image (Image, 'color/color_fuses_00')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* ****
* step: 为颜色空间转换创建查找表
* ****
create_color_trans_lut ('hsv', 'from_rgb', 8, ColorTransLUTHandle)
for Count := 0 to 4 by 1
    * ****
    * step: 获取图片(前面之所以写了read_image我估计是先设置图形窗口信息)
    * ****
    read_image (Image, 'color/color_fuses_0' + Count)
    dev_display (Image)
    disp_message (WindowHandle, 'color/color_fuses0' + Count +'.png', 'window', 12, 512, 'black', 'true')
    * ****
    * step: 通过S分量得到不同颜色的熔断器H分量区域
    * ****
    decompose3 (Image, Red, Green, Blue)
    apply_color_trans_lut (Red, Green, Blue, Hue, Saturation, Intensity, ColorTransLUTHandle)
    threshold (Saturation, Saturated, 60, 255)
    reduce_domain (Hue, Saturated, HueSaturated)
    Output := []
    for Fuse := 0 to |FuseTypes|-1 by 1
        * ****
        * step: 通过不同颜色具有不同色调区间及其他技术对熔断器进行分类
        * ****
        threshold (HueSaturated, CurrentFuse, HueRanges[Fuse*2], HueRanges[Fuse*2+1])
        connection (CurrentFuse, CurrentFuseConn)
        fill_up (CurrentFuseConn, CurrentFuseFill)
        select_shape (CurrentFuseFill, CurrentFuseSel, 'area', 'and', 6000, 20000)
        area_center (CurrentFuseSel, FuseArea, Row1, Column1)
        dev_set_color ('magenta')
        for i := 0 to |FuseArea|-1 by 1
            disp_message (WindowHandle, FuseColors[Fuse] + ' ' +FuseTypes[Fuse]+' Ampere', 'image', Row1[i]+40, Column1[i]-100, DisplayColors[Fuse], 'true')
        endfor
        Output := [Output,FuseColors[Fuse] + ' Fuses: ' + |FuseArea|]
    endfor
    disp_message (WindowHandle, Output, 'window', -1, -1, DisplayColors, 'true')
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
endfor
dev_update_on ()
dev_close_window ()

总结:

  1. 上面两个例子都是从RGB颜色空间转到SHV颜色空间。利用饱和度S分量对目标区域进行粗分割,得到高饱和区域;其后再利用色调H分量在不同颜色时具有不同区间进行精分割,最后做一些其他处理得到最终的结果。
  2. 在这个思路中用到的都是S和H两个分量,不知道有没有用到三个分量的例子。
  3. 在第一个例子中,白底(饱和度为零)采用S分量进行粗分割,我觉得如果换成黑底(亮度为零)可以采用V分量进行粗分割。
  4. 相对而言比较简单,容易实现;但是对光照敏感,不稳定。

2.第二种思路:使用颜色等多特征进行训练、学习识别

废话不多说,下面的历程(代码)可以在 运用例程->颜色检测->color_pieces.hdev 找到。

* color_pieces.hdev: completeness check of colored game pieces using MLP classification
dev_update_window ('off')
dev_close_window ()
dev_open_window (0, 0, 557, 416, 'black', WindowHandle)
dev_set_draw ('margin')
ImageRootName := 'color/color_pieces_0'
Regions := ['黄色','粉色','蓝色','背景']
Highlight := ['goldenrod','magenta','cyan']
*创建一个空区域对象,用于保存训练样本
gen_empty_obj (Classes)
*下面这个循环里一个是用彩色图片训练网络,一个用模拟的灰度图片训练网络。
*从最后的结果来看,用彩色的图片训练的网络能更好的完成任务;而用模拟的
*灰度图片训练的网络分类效果不是很好。这说明颜色特征还是非常有用的。
for Mode := 0 to 1 by 1
    dev_set_color ('black')
    read_image (Image, ImageRootName+'0')
    if (Mode=1)
        * 模拟灰色图像
        rgb1_to_gray (Image, GrayImage)
        compose3 (GrayImage, GrayImage, GrayImage, Image)
    endif
    dev_display (Image)
    if (Mode=0)
        * ***
        * 1 生成训练样本(指定颜色类别)
        * ***
        for i := 1 to 4 by 1
            dev_display (Image)
            dev_display (Classes)
            disp_message (WindowHandle, ['在' + Regions[i-1] + '区域画一个矩形','点击鼠标右键确认'], 'window', 24, 12, 'black', 'false')
            *注意:画矩形的时候,不要把背景信息包括进去了;否则,检测效果会不好的
            draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
            gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
            concat_obj (Classes, Rectangle, Classes)
        endfor
    endif
    * ***
    * 训练多层感知机网络
    * ***
    * 2.1 创建并设置多层感知机网络参数
    create_class_mlp (3, 7, 4, 'softmax', 'normalization', 3, 42, MLPHandle)
    * 2.2 把训练样本添加到网络中
    add_samples_image_class_mlp (Image, Classes, MLPHandle)
    set_tposition (WindowHandle, 100, 12)
    write_string (WindowHandle, 'Training...')
    * 2.3 训练多层感知机网络
    train_class_mlp (MLPHandle, 400, 0.5, 0.01, Error, ErrorLog)
    for img := 0 to 3 by 1
        read_image (Image, ImageRootName + img)
        if (Mode=1)
            rgb1_to_gray (Image, GrayImage)
            compose3 (GrayImage, GrayImage, GrayImage, Image)
        endif
        * ***
        * 在随后的图片中使用多层感知机分类物品
        * ***
        * 使用网络去分类物品
        classify_image_class_mlp (Image, ClassRegions, MLPHandle, 0.5)
        dev_display (Image)
        disp_message (WindowHandle, '查看每一种颜色的棋子是否有四个...', 'window', 24, 12, 'black', 'false')
        dev_set_line_width (2)
        * 下面的循环是显示结果
        for figure := 1 to 3 by 1
            copy_obj (ClassRegions, ObjectsSelected, figure, 1)
            connection (ObjectsSelected, ConnectedRegions)
            select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 400, 99999)
            count_obj (SelectedRegions, Number)
            dev_set_color (Highlight[figure-1])
            dev_display (SelectedRegions)
            OutString := Regions[figure-1] + ': ' +Number+'   '
            dev_set_color ('green')
            disp_message (WindowHandle, OutString, 'window', 24+30*figure, 12, 'black', 'false')
            if (Number#4)
                disp_message (WindowHandle, 'Not OK', 'window', 24+30*figure, 70, 'black', 'false')
            else
                disp_message (WindowHandle, 'OK', 'window', 24+30*figure, 70, 'green', 'false')
            endif
        endfor
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endfor
endfor
dev_set_line_width (1)
dev_set_draw ('fill')
dev_clear_window ()

总结,使用多层感知机的步骤及细节:

  1. 制作训练样本
    draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
    gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
    concat_obj (Classes, Rectangle, Classes)
  2. 训练多层感知机网络
    2.1 创建并设置多层感知机网络参数(因为是三通道的彩色图片,所以第一参数是3;隐藏层的参数选择没有标准,姑且选后一个参数的两倍左右;后一个参数是输出参数,因为这里有三种颜色的棋子,加上背景,总共输出四种,所以填4;其他参数课选择的范围小)
          create_class_mlp (3, 7, 4, 'softmax', 'normalization', 3, 42, MLPHandle)
    2.2 把训练样本添加到网络中
          add_samples_image_class_mlp (Image, Classes, MLPHandle)
    2.3 训练多层感知机网络
          train_class_mlp (MLPHandle, 400, 0.5, 0.01, Error, ErrorLog)
  3. 使用网络去分类物品
    classify_image_class_mlp (Image, ClassRegions, MLPHandle, 0.5)

你可能感兴趣的:(Halcon)