骰子定位识别

引言

一年前我还在上海从事过机器视觉软件的开发,时光荏苒。这是在公司期间做了一个有趣的项目,现讲一下其主要思想及如何实现。

先来看一下效果图,Look

嗯,看的出来,虽然背景光线不均匀,虽然骰子挨的那么近,还是很好的识别出来,程序的健壮性很强嘛。PS.为避免不必要的麻烦,我将自己的姓名和联系方式马赛克掉,嘿嘿。

这里程序的主要功能是识别出场景中存在多少粒骰子,以及每个骰子的位置,点子数,还有一些其他统计信息。当然,这只是一个机器视觉里的一个小Demo,可以继续完善。

思路

这是怎么做到的呢?这属于模式识别问题了。思路如下:

  1. 首先需要将目标(这里是整个骰子区域)从背景中正确分离出来;
  2. 将目标正确分离开来,即骰子之间要分离正确;
  3. 对单个骰子进行阈值分割,统计其中心坐标。

问题的关键点在于,第一步中如何正确将目标从背景中分离以及第二步沾黏的物体如何分离开来。

方法

顶帽变换

非均匀光照的最终结果导致了区域的分割错误(一些区域错误地分类了),且骰子的某些部分没有提取出来。顶帽变换的一个重要用途就是校正不均匀光照的影响。

顶帽(Top-hat)变换

原图像与开运算结果图之差。

dst=tophat(src,element)=src?open(src,element)

与顶帽变换相反的是底帽(bottom-hat)变换:

闭运算结果图与原图像之差。

dst=blackhat(src,element)=close(src,element)?src

下面分割花生为例。用手机在室内环境下将花生放在黑色鼠标垫上拍摄的。没有额外打光,只是打开相机的闪灯光,拍摄效果还行。但是,这样的结果很容易受到光照影响,可以看出,图像中间最为明亮,边缘都有些黑暗,对比度不是太明显。用一个半径为40的圆盘形结构元进行开运算,可以看出图像背景已经均匀了,有点类似于执行了一次滤波操作。图3-4依次展示了顶帽变换之后的图像(图像减去其开操作),底帽变换之后的图像(闭操作减去原图像),顶帽变换联合底帽变换(原图像加上顶帽变换减去底帽变换)。经过处理之后的图像对比度明显变大,这样经过阈值分割之后,就可以得到正确的分割结果了。

距离变换与分水岭算法

距离变换

距离变换图算法是一种针对栅格图像的特殊变换,是把二值图像变换为灰度图像,其中每个像素的灰度值等于它到栅格地图上相邻物体的最近距离。目前被广泛应用于计算机图形学、GIS空间分析和模式识别等领域。

按距离类型划分,距离变换可分为:非欧氏距离变换和欧氏距离变换(EDT)。其中EDT精度高,与实际距离相符,应用更广泛。

基本思想是把离散分布在空间中的目标根据一定的距离定义方式生成距离图, 其中每一点的距离值是到所有空间目标距离中最小的一个。

基于“欧几里德距离”公式的距离变换图算法 :

在二维平面上定义两点,那么他们之间的欧氏距离表示为 :

D=(x1?x2)2+(y1?y2)2???????????????????√

在二值图像中,1代表目标点,0代表背景;在灰度图像中,栅格的灰度值表示该栅格点到最近目标点的距离值。这样一张M×N的图像可以表示为一个二维数组A[M][N],其中A[i][j]=1对应的栅格表示目标点,A[i][j]=0对应的栅格表示背景点。设B=(x,y)|A[i][j]=1为目标点集合,则欧氏距离变换就是对A中所有的栅格点求:

D[i][j]=min{Distance[(i,j),(x,y)]}

其中 ,从而得到二值图像A的欧氏距离变换图。

分水岭算法

分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。

直接应用分水岭分割算法的效果往往并不好,通常会由于噪声和梯度的其他局部不规则形造成过度分割。所以在图像中先用距离变换、梯度或者控制标记符对前景对象和背景对象进行标注区别,再应用分水岭算法会取得较好的分割效果。

使用距离变换的分水岭分割如图所示。经过从图中可以看出,区域被很好的分割开了,结果是令人满意的。

统计信息

将分水岭分割后的区域与二值图像做交集,就可以得到分割后的目标区域。对每一个目标区域去求它的面积,周长等感兴趣信息。很多图像处理函数库都有计算面积、周长等图像处理基础的算子。

代码

这里,我使用的了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日 [email protected]

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-23 04:58:25

骰子定位识别的相关文章

汽车车牌定位识别系统的设计实现

http://www.eeworld.com.cn/qrs/2015/1023/article_25403.html 一.项目背景及可行性分析 2.1 项目背景及技术难点 项目名称:智能交通:汽车车牌定位识别: 项目内容:本项目是在FPGA前端实时完成图像采集.预处理.车牌定位和字符分割以及数据传输工作,在后端完成车牌字符识别工作.FPGA接收采集的实时图像,在内部采用流水线方式依次完成图像预处理.车牌定位和车牌字符分割工作,最后通过高速USB端口将已分割字符传输到后端进行字符识别.其中,图像采

骰子点数识别-图像分割

前言 前段时间借用神经网络和卷积神经网络实现了骰子点数的识别,但是一个很严重的问题一直困扰我,那就是当两个骰子叠在一起的时候,将两个骰子分开并不是一件简单的事情. 下图是我在识别过程中产生的不能识别的,叠加在一起的图片素材. 面对这些形态各异的图片,有的时候是两个骰子一个角连在一起,有的是一条边,有的是三个骰子叠在一起.所以,很难找到一个满意的办法解决这个问题. 第一思路就是从原始的RGB图像着手,通过调整二值化阈值,希望能够将骰子对象分割开来,但是遗憾的是我试了好几种方法,都是不行的,原因在于

selemiun 下拉菜单、复选框、弹框定位识别

一.下拉菜单识别 对下拉框的操作,主要是通过Select 类里面的方法来实现的,所以需要new 一个Select 对象(org.openqa.selenium.support.ui.Select)来进行操作 public void selectDemo() throws InterruptedException { driver.get("http://tieba.baidu.com/f/search/adv?red_tag=v3168911135"); driver.manage()

车牌识别LPR(一)-- 研究背景

在年尾用了几天的时间将2014年的所有工作都总结了一遍,将之前的文档综合了下. 以下是LPR系统,车牌识别的一些总结资料. 第一篇:LPR研究背景 汽车的出现改变了以往出行徒步和以马代步的时代,极大地改变了人们的生活方式,扩大了人们的活动范围,加强了人与人之间的交流.全世界的汽车拥有量呈爆炸性增长,汽车虽方便了我们的出行,但同时也造成了城市交通压力,应用现代科技解决汽车不断增长而出现的交通问题已经成为一项重要的研究课题,智能交通系统应孕而出. 智能交通系统(Intelligent Transpo

毕业设计 python opencv实现车牌识别 界面

主要代码参考https://blog.csdn.net/wzh191920/article/details/79589506 GitHub:https://github.com/yinghualuowu 答辩通过了,补完~ 这里主要是用两种方法进行定位识别 # -*- coding: utf-8 -*- __author__ = '樱花落舞' import tkinter as tk from tkinter.filedialog import * from tkinter import ttk

CSS3画一个滚动的骰子

今天利用CSS3来画一个自动滚动的骰子. 思路:骰子的六个面分别用六个ul标签,每个面的点数就是li标签,点数的排列采用伸缩布局,然后采用定位和transform属性将六个面翻转折叠成立方体. 1.HTML结构:用一个类名为box的大盒子将六个面(ul)包起来,方便给整个骰子定位和添加动画:每个ul里的li代表每个面的点数,其中第四.五.六面每一列的点数分别用一个div包起来 1 <div class="box"> 2 <ul class="one"

如何阅读源代码(8)

第九章: 系统构架 ++++++++++++++ 182.一个系统可以(在重大的系统中也确实如此)同时出多种不同的构架类型. 以不同的方式检查同一系统|分析系统的不同部分|或使用不同级别的分解, 都有可能发现不同的构架类型. 183.协同式的应用程序, 或者需要协同访问共享信息或资源的半自治进程, 一般会采用集中式储存库构架. 184.黑板系统使用集中式的储存库, 存储非结构化的键/值对, 作为大量不同代码元件之间的通信集线器. 185.当处理过程可以建模|设计和实现成一系列的数据变换时, 常常

怎么学习阅读大型项目的代码

第一章: 导论 ++++++++++++ 1.要养成一个习惯, 经常花时间阅读别人编写的高品质代码. 2.要有选择地阅读代码, 同时, 还要有自己的目标. 您是想学习新的模式|编码风格|还是满足某些需求的方法. 3.要注意并重视代码中特殊的非功能性需求, 这些需求也许会导致特殊的实现风格. 4.在现有的代码上工作时, 请与作者和维护人员进行必要的协调, 以避免重复劳动或产生厌恶情绪. 5.请将从开放源码软件中得到的益处看作是一项贷款, 尽可能地寻找各种方式来回报开放源码社团. 6.多数情况下,

python Chrome 开发者模式消失的方法

最近使用 Chrome浏览器跑Selenium Python 自动化脚本运行过程中,总是出现这样的对话框  出现这样的对话框,如果不能自动关闭,这个对话框会影响web端页面的其他链接的定位识别,这样就会导致该脚本就没法正常完成. 想过多种方法,如何关闭开发者模式等方法,在本地的时候,已经手动关闭了开发者模式,但是在运行脚本的过程中,该对话框一直存在.最后无解,在处理脚本过程中,为了规避这个对话框,我采取的方法是,在输入URL后,就将打开的页面设置最大化,即在适当的位置输入 driver.maxi