先说一下RGB和HSV这两种颜色空间。大部分人可能接触RGB这种颜色空间多一些,相较于人这种颜色空间对硬件更加友好;而HSV更符合人的视觉感观,对人友好,如果你是画家、设计师,接触的可能会多一些。H是色调,表示是哪种颜色,取值是0到360度,比如0表示是红色;S表示是饱和度,取值0%到100%,越鲜艳值就越高,颜色越淡值越小;V表示亮度,取值0%到100%,越白值越大,越暗值越小。
下面的一个例子展示的是在不同颜色的线中分割出黄色的线。其大致思路是,先转到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 ()
总结:
废话不多说,下面的历程(代码)可以在 运用例程->颜色检测->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 ()
总结,使用多层感知机的步骤及细节: