现在位置首页 / 项目实战 /正文

aforge.net扑克牌识别的技术实现(1)

作者: IT小兵 | 2016年8月9日| 热度:℃ | 评论: |参与:

在以前的几篇文章中,提到了aforge的使用。[wpf教程-AForge.net调用摄像头/切换摄像头/保存图片及像素问题] [wpf控件-几个调用摄像头开源控件的使用说明及问题(WPFMediaKit/WpfCap/AForge.net)]

今天分享一下aforge.net扑克牌识别的技术实现.

介绍

 

(图片上的字:方块4,方块J,黑桃2

用机器人配上扑克牌识别系统,就可以在二十一点一类的扑克游戏中扮演荷官或是人类玩家的角色。实现这样的程序同样也是学习计算机视觉和模式识别的好途径。

本文涉及到的AForge.NET框架技术有二值化、边缘检测、仿射变换、BLOB处理和模板匹配算法等。

需要注意的是,这篇文章和文中介绍的系统是针对英美扑克设计的,可能不适用于其他种类的扑克。然而,本文描述了扑克的检测和识别的基本方法。因此,具体的识别算法需要根据扑克牌型特点而加以变化。

这里有一个视频演示。

(已经搬运到优酷——野比注)

 © 版权所有 野比 2012 

扑克检测

我们需要检测图像(指采集到的视频画面,下同——野比注)上的扑克对象,以便能进行下一步的识别。为了完成检测,我们会用一些图像滤镜对视频画面进行处理。

第一步,将图像去色(即灰度化——野比注)。去色是将彩色图像转换成8bit图像的一种操作。我们需要将彩色图像转换为灰度图像以便对其进行二值化。

我们把彩色图像转为灰度图像后,对其进行二值化。二值化(阈值化)是将灰度图像转换为黑白图像的过程。本文使用Otsu的方法进行全局阈值化。

1 Bitmap temp = source.Clone() as Bitmap; // 复制原始图像
2 
3 FiltersSequence seq = new FiltersSequence();
4 seq.Add(Grayscale.CommonAlgorithms.BT709);  // 添加灰度滤镜
5 seq.Add(new OtsuThreshold()); // 添加二值化滤镜
6 temp = seq.Apply(source); // 应用滤镜

 

(图片上的字:原始图像、灰度图像、二值(黑白)图像)

有了二值图像后,就可以用BLOB处理法检测扑克牌了。我们使用AForge.NetBlobCounter类完成这项任务。该类利用连通区域标记算法统计并提取出图像中的独立对象(即扑克牌——野比注)。

1 // 从图像中提取宽度和高度大于150的blob
2 BlobCounter extractor = new BlobCounter();
3 extractor.FilterBlobs = true;
4 extractor.MinWidth = extractor.MinHeight = 150;
5 extractor.MaxWidth = extractor.MaxHeight = 350;
6 extractor.ProcessImage(temp);

执行完上述代码后,BlobCounter类会滤掉(去除)宽度和高度不在[150,350]像素之间的斑点(blob,即图块blob,图像中的独立对象。以下将改称图块——野比注)。这有助于我们区分出图像中其他物体(如果有的话)。根据测试环境的不同,我们需要改变滤镜参数。例如,假设地面和相机之间距离增大,则图像中的扑克牌会变小。此时,我们需要相应的改变最小、最大宽度和高度参数。

现在,我们可以通过调用extractor.GetObjectsInformation()方法得到所有图块的信息(边缘点、矩形区域、中心点、面积、完整度,等等)。然而,我们只需要图块的边缘点来计算矩形区域中心点,并通过调用PointsCloud.FindQuadriteralCorners函数来计算之。

1 foreach (Blob blob in extractor.GetObjectsInformation())
2 {
3  // 获取扑克牌的边缘点
4  List< IntPoint > edgePoints = extractor.GetBlobsEdgePoints(blob);
5  // 利用边缘点,在原始图像上找到四角
6  List< IntPoint > corners =  PointsCloud.FindQuadrilateralCorners(edgePoints);
7 }

(图片上的字:在图像上绘制边缘点、寻找每张扑克的角)

找到扑克牌的四角后,我们就可以从原始图像中提取出正常的扑克牌图像了。由上图可以看出,扑克牌可以横放。扑克牌是否横放是非常容易检测的。在扑克牌放下后,因为我们知道,牌的高度是大于宽度的,所以如果提取(转化)图像的宽度大于高度,那么牌必然是横放的。随后,我们用RotateFlip函数旋转扑克牌至正常位置。

注意,为了正确识别,所有的扑克应当具有相同的尺寸。不过,鉴于相机角度不同,扑克牌的尺寸是会变化的,这样容易导致识别失败。为了防止这样的问题,我们把所有变换后的扑克牌图像都调整为200x300(像素)大小。

1 // 用于从原始图像提取扑克牌
 2 QuadrilateralTransformation quadTransformer = new QuadrilateralTransformation();
 3 // 用于调整扑克牌大小
 4 ResizeBilinear resizer = new ResizeBilinear(CardWidth, CardHeight);
 5 
 6 foreach (Blob blob in extractor.GetObjectsInformation())
 7 {
 8      // 获取扑克牌边缘点
 9      List<IntPoint> edgePoints = extractor.GetBlobsEdgePoints(blob);
10      // 利用边缘点,在原始图像上找到四角
11      List<IntPoint> corners =  PointsCloud.FindQuadrilateralCorners(edgePoints);
12      Bitmap cardImg = quadTransformer.Apply(source); // 提取扑克牌图像
13 
14      if (cardImg.Width > cardImg.Height) // 如果扑克牌横放
15           cardImg.RotateFlip(RotateFlipType.Rotate90FlipNone); // 旋转之
16      cardImg =  resizer.Apply(cardImg); // 归一化(重设大小)扑克牌
17        .....
18 }

(图片上的字:使用QuadriteralTransformation类从原始图像提取出的扑克牌。该类利用每张牌的四角进行变换。)

到目前为止,我们已经找到了原始图像上每张扑克牌的四角,并从图像中提取出了扑克牌,还调整到统一的尺寸。现在,我们可以开始进行识别了。

 

下一篇 继续讲解:

识别扑克牌

点击阅读本文所属分类的更多文章: 项目实战 。和高手一起交流:346717337
友荐云推荐

未注明转发、原文均为本站原创。分享本文请注明 原文链接

给您更多信息和帮助

在这里您可以找到更多:

技术交流群:346717337 Jquery插件交流

投稿:suchso@vip.qq.com

承接:企业网站门户/微网站/微商城/CMS系统/微信公众号运营/业务咨询

抢天猫双11红包
推荐使用阿里云服务器
echarts教程系列
本月最热文章

微信扫一扫,徜徉悠嘻网,您的休闲乐园

微信公众号:快乐每一天

随机文章
标签

技术交流群:346717337

投稿:suchso@vip.qq.com

专业专注:企业网站门户/微网站/微商城/CMS系统/微信公众号运营/付费问题咨询