一年前我还在上海从事过机器视觉软件的开发,时光荏苒。这是在公司期间做了一个有趣的项目,现讲一下其主要思想及如何实现。
先来看一下效果图,Look
嗯,看的出来,虽然背景光线不均匀,虽然骰子挨的那么近,还是很好的识别出来,程序的健壮性很强嘛。PS.为避免不必要的麻烦,我将自己的姓名和联系方式马赛克掉,嘿嘿。
这里程序的主要功能是识别出场景中存在多少粒骰子,以及每个骰子的位置,点子数,还有一些其他统计信息。当然,这只是一个机器视觉里的一个小Demo,可以继续完善。
这是怎么做到的呢?这属于模式识别问题了。思路如下:
问题的关键点在于,第一步中如何正确将目标从背景中分离以及第二步沾黏的物体如何分离开来。
非均匀光照的最终结果导致了区域的分割错误(一些区域错误地分类了),且骰子的某些部分没有提取出来。顶帽变换的一个重要用途就是校正不均匀光照的影响。
顶帽(Top-hat)变换
:
原图像与开运算结果图之差。
底帽(bottom-hat)变换
: 距离变换图算法是一种针对栅格图像的特殊变换,是把二值图像变换为灰度图像,其中每个像素的灰度值等于它到栅格地图上相邻物体的最近距离。目前被广泛应用于计算机图形学、GIS空间分析和模式识别等领域。
按距离类型划分,距离变换可分为:非欧氏距离变换和欧氏距离变换(EDT)。其中EDT精度高,与实际距离相符,应用更广泛。
基本思想是把离散分布在空间中的目标根据一定的距离定义方式生成距离图, 其中每一点的距离值是到所有空间目标距离中最小的一个。
基于“欧几里德距离”公式的距离变换图算法 :
在二维平面上定义两点,那么他们之间的欧氏距离表示为 :
分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
直接应用分水岭分割算法的效果往往并不好,通常会由于噪声和梯度的其他局部不规则形造成过度分割。所以在图像中先用距离变换、梯度或者控制标记符对前景对象和背景对象进行标注区别,再应用分水岭算法会取得较好的分割效果。
使用距离变换的分水岭分割如图所示。经过从图中可以看出,区域被很好的分割开了,结果是令人满意的。
将分水岭分割后的区域与二值图像做交集,就可以得到分割后的目标区域。对每一个目标区域去求它的面积,周长等感兴趣信息。很多图像处理函数库都有计算面积、周长等图像处理基础的算子。
这里,我使用的了Halcon说明,但所幸代码很短,而且Halcon支持生成其他语言,代码也容易理解,可以改成其他语言的。注意,我这里没有添加消除不均匀光影响的代码。
dev_close_window()
dev_open_window (0, 0, 744, 480, ‘black‘, WindowHandle)
for Num := 1 to 10 by 1
read_image (Image, Num+‘.bmp‘)
get_image_size (Image, Width, Height)
dev_set_colored (12)
decompose3 (Image, ImageR, ImageG, ImageB)
threshold (ImageR, Region, 100, 255)
fill_up (Region, RegionFillUp)
connection (RegionFillUp, ConnectedRegions)
********************距离变换算法*************************
distance_transform (ConnectedRegions, DistanceImage, ‘octagonal‘, ‘true‘, 744, 480)
convert_image_type (DistanceImage, DistanceImageByte, ‘byte‘)
invert_image (DistanceImageByte, DistanceImageInv)
scale_image_max (DistanceImageInv, DistanceImageInvScaled)
*******************提取分水岭和盆地***********************
watersheds_threshold (DistanceImageInv, Basins, 5)
*******************取交集*******************************
intersection (Basins, ConnectedRegions, SegmentedDices)
dev_display (Image)
dev_display (SegmentedDices)
count_obj (SegmentedDices, Number)
Sum:=0
Min:=6
Max:=0
for Index := 1 to Number by 1
select_obj (SegmentedDices, Obj, Index)
reduce_domain (ImageB, Obj, ImageReduced)
mean_image (ImageReduced, ThresholdImage, 31, 31)
dev_display (ImageReduced)
dyn_threshold (ImageReduced, ThresholdImage, RegionDynThresh, 20, ‘dark‘)
erosion_circle (RegionDynThresh, RegionErosion, 1.5)
connection (RegionErosion, ConnectedDotRegions)
select_shape (ConnectedDotRegions, ConnectedDotRegions, [‘area‘,‘roundness‘], ‘and‘, [150,0.5808], [950,1])
count_obj (ConnectedDotRegions, DotNumber)
if(Max<DotNumber)
Max:=DotNumber
endif
if(Min>DotNumber)
Min:=DotNumber
endif
Sum:=Sum+DotNumber
area_center (Obj, Area, CenterY, CenterX)
disp_message (WindowHandle, ‘点数:‘+DotNumber+‘(‘+CenterX$‘.1f‘+‘,‘+CenterY$‘.1f‘+‘)‘, ‘image‘, CenterY, CenterX, ‘red‘, ‘false‘)
endfor
disp_message (WindowHandle, ‘区域内共有:‘+Number+‘个骰子‘, ‘image‘, 20, 20, ‘red‘, ‘false‘)
disp_message (WindowHandle, ‘点数之和:‘+Sum, ‘image‘, 40, 20, ‘red‘, ‘false‘)
disp_message (WindowHandle, ‘最小点数:‘+Min+‘ 最大点数:‘+Max, ‘image‘, 60, 20, ‘red‘, ‘false‘)
disp_continue_message (WindowHandle, ‘black‘, ‘true‘)
stop ( )
endfor
数字图像处理(第三版) 冈萨雷斯著 chapter 9.6, 灰度级形态学
数字图像处理(第三版) 冈萨雷斯著 chapter 10.5, 使用形态学分水岭的分割
作者 | 日期 | 联系方式 |
---|---|---|
风吹夏天 | 2015年8月5日 | wincoder@qq.com |
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/bluecol/article/details/47285593