前言

首先要明确我们的任务。要想解数独,需要进行计算,图片格式的数字肯定是不行的,所以必须把图片上的数字转换为实实在在的数字才能进行计算。要得到实实在在的数字,我们需要做的是对图片上的数字进行提取和识别。本文先说第一步,图片中数字的提取。

在一年之前,我曾用C++尝试过opencv解数独,但由于当时水平有限,未能完成。当时的成果就是透视变换的应用和方格数字的提取。现在稍微简化一下工作,不再从倾斜的数独图片中提取数独,而是直接用正拍且已经提取好的数独开始处理。这里用到的数独图片如下图所示:

方法

1.以前的方法

从上图这样的九宫格图片中提取数字,我以前用的方法是,先利用轮廓提取,通过轮廓的面积进行筛选,得到所有的81个小方格;然后对检测小方格中是否有黑色像素以及像素的多少(排除噪音)来判定哪个小方格中有数字;最后对有数字的小方格再次进行轮廓提取得到数字的轮廓和轮廓外包矩形。

此方法实现起来相对来说比较麻烦,思路仅供参考。

2.本次所用方法

在仔细研究了opencv轮廓提取函数findContours()之后,发现利用轮廓的层级结构会更加简单。作为本节最主要的函数,有必要稍微多说几句。

cv2.findContours(image, mode, method[, contours[, hierarchy[, offset] ] ]) → contours, hierarchy

在Python中,findContours()接受如下参数并返回contours和hierarchy。

1.image 源图像,一般为8为单通道图像,更具体来说,二值图像。其他情况暂且不论。

2.mode 轮廓检索模式,简要介绍几种:

  • cv2.RETR_EXTERNAL 只检测外轮廓。对所有轮廓设置hierarchy[i][2]=hierarchy[i][3]=-1
  • cv2.RETR_LIST 提取所有轮廓,并放置在list中,检测到的轮廓不建立等级关系。
  • cv2.RETR_TREE 提取所有轮廓,建立网状的轮廓结构。

3.method 轮廓的近似办法,是提取轮廓上所有像素点,还是只提取关键的一些点。比如一条线段是提取所有点还是只提取两个端点。

4.contours 检测到的轮廓,为组成轮廓的点集。

5.hierarchy 下面详述。

hierarchy

什么是层级结构呢?我们检测轮廓的时候,有时候可能会出现其中一个轮廓包含了另外一个轮廓,比如同心圆。这里我们认为外侧轮廓为父轮廓,内侧被包含的为子轮廓。同一级别的又有前一个轮廓后一个轮廓。总的来说,hierarchy表达的是不同轮廓之间的 关系和联系。

这样,每一个轮廓都会有[Next, Previous, First_Child, Parent]

上面说到,cv2.RETR_EXTERNAL 只检测外轮廓。对所有轮廓设置hierarchy[i][2]=hierarchy[i][3]=-1。由于只检测最外围轮廓,所有检测到的轮廓肯定没有父轮廓和子轮廓,所有层级结构的第三个和第四个元素都设置为-1。

看下图:

如果只检测最外围轮廓,那么只会检测到轮廓012

如果建立层级关系,以轮廓3为例,那么它的父轮廓是2a,子轮廓是3a,没有前一轮廓和后一轮廓,设为-1。所以它的hierarchy应该是[-1,-1,3a,2a]

如果是轮廓2,那么它的前一轮廓就是1,子轮廓是2a,没有后一轮廓和父轮廓。所以它的hierarchy应该是[-1,1,2a,-1]

有兴趣的可以仔细看看,没兴趣的可以略过。兴趣更浓的可以去看opencv文档,那里的讲解更加详细。

这里就说这么多,对于我们本节的内容来说,已经够了。

上面说了啥

我觉得大部分人这个时候还会问,上面说了这么一堆到底是要干什么???因为这里确实不是那么清晰明了。

别忘了我们本节的目的是要提取数字,什么样的轮廓包含数字?

一般来说经过前面的阈值分割得到二值图像,然后从二值图像中提取的轮廓是这样的。这是处理的比较好的情况下:

显然最最外面的那个包围所有的就是0号轮廓,里面的九九八十一个小方格就是0号轮廓的子轮廓。而每一个已知数字的轮廓都是对应方格的子轮廓。

提取数字

所有我们的办法就是先提取方格,然后提取数字。

八十一个小方格有什么特点?父轮廓都是0号轮廓!所以:

boxes = []
for i in range(len(hierarchy[0])):if hierarchy[0][i][3] == 0:boxes.append(hierarchy[0][i])

不记得的可以上翻看一下hierarchy是不是第四个元素表示父轮廓。

然后从小方格中提取数字轮廓。数字轮廓的有什么特点?其父轮廓有子轮廓,也即是说包含子轮廓的小方格里面就有数字。所以:

for j in range(len(boxes)):if boxes[j][2] != -1:x,y,w,h = cv2.boundingRect(contours[boxes[j][2]])number_boxes.append([x,y,w,h])

不记得的可以上翻看一下hierarchy是不是第三个元素表示子轮廓。不等于-1表示存在。

最后把检测到的数字画出来就可以得到下面的这幅图了。

代码

# -*- coding: UTF-8 -*-
import cv2img = cv2.imread('001.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
## 阈值分割
ret,thresh = cv2.threshold(gray,200,255,1)## 对二值图像执行膨胀操作
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(5, 5))
dilated = cv2.dilate(thresh,kernel)## 轮廓提取,cv2.RETR_TREE表示建立层级结构
image, contours, hierarchy = cv2.findContours(dilated,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)## 提取小方格,其父轮廓都为0号轮廓
boxes = []
for i in range(len(hierarchy[0])):if hierarchy[0][i][3] == 0:boxes.append(hierarchy[0][i])## 提取数字,其父轮廓都存在子轮廓
number_boxes = []
for j in range(len(boxes)):if boxes[j][2] != -1:#number_boxes.append(boxes[j])x,y,w,h = cv2.boundingRect(contours[boxes[j][2]])number_boxes.append([x,y,w,h])img = cv2.rectangle(img,(x-1,y-1),(x+w+1,y+h+1),(0,0,255),2)cv2.namedWindow("img", cv2.WINDOW_NORMAL);
cv2.imshow("img", img)
cv2.waitKey(0) 

下一步

数字已经提取出来,下一步就该是数字的识别了…


公众号CVPy,分享OpenCV和Python的实战内容。每一篇都会放出完整的代码。欢迎关注。

OpenCV玩九宫格数独(一)——九宫格图片中提取数字相关推荐

  1. OpenCV 玩九宫格数独(二):knn 数字识别

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者:刘潇龙 前言 首先需要说明,这里所说的数字识别不是手写数字识别! 但凡对机器学习有所了解的人,相信看到数 ...

  2. OpenCV玩九宫格数独(三):九宫格生成与数独求解

    前言 在此之前,OpenCV玩九宫格数独(一)和(二)分别介绍了如何从九宫格图片中提取出已知数字和如何用knn训练数字识别模型.在这些前期工作都已经完成的基础上,接下来我们需要做什么呢? 我们要做的有 ...

  3. OpenCV实践之路——opencv玩数独之一九宫格轮廓提取与透视变换

    本文由@星沉阁冰不语出品,转载请注明作者和出处. 文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/50783585 微博:http ...

  4. OpenCV玩九宫格数独(零)——预告篇

    九宫格 数独源于18世纪的瑞士,又称九宫格,有九行.久列和九宫.玩家需要在九宫格中,根据已知的数字,利用逻辑和推理能力,填出所有的空格中应有的数字.填的时候要求每行.每列和每宫都要不重复地包含数字0- ...

  5. OpenCV玩九宫格数独(二):knn数字识别

    参考: 1.http://blog.csdn.net/xingchenbingbuyu/article/details/70208199 2.https://github.com/LiuXiaolon ...

  6. 数独游戏技巧从入门到精通_如何引导孩子入门九宫格数独?掌握4个技巧口诀,孩子思维提升快...

    九宫格数独对孩子的思维训练有着非常不错的效果,我们完全可以用其培养孩子对数字的兴趣,并培养孩子严谨的逻辑推理态度. 那九宫格数独有没有技巧口诀呢? 对于孩子来说,过于复杂的技巧他们也掌握不了.所以,我 ...

  7. 9x9九宫格java_9x9九宫格数独填写规律

    9x9九宫格数独填写规律是一款画面简约精致的魔性消除玩法手机游戏,9x9九宫格数独填写规律游戏音效超级的悦耳,令人兴趣,玩家可以过把不同方块拼成九宫格,或者是行列斜线的方式来进行消除. 游戏介绍 1. ...

  8. Python + OpenCV + DeepLearning 解数独问题【一、数独的提取】

    整个解数独问题可以大致分为3个部分: 从图片中提取出完整的数独[本文的部分] 从数独中提取出数字并传入神经网络进行预测 解出数独 [环境] Python:3.8.5 OpenCV:4.5.1 Kera ...

  9. 微信小程序版 九宫格数独游戏

    前言 继上次JAVA版的九宫格数独,这几天把java版的迁移到了小程序这边,写一篇记录一下. 核心还是在算法上,话不多说,直接干代码 一.核心算法 先把81个格子填满,填充之前需要先判断当前格子填的数 ...

  10. java九宫格问题课程设计_课程设计九宫格数独.doc

    课程设计九宫格数独 中南民族大学管理学院 学生课程设计报告 课题名称: java课程设计 选题名称: 九宫格数独 年 级: 2009 专 业: 信息管理与信息系统 学 号: 姓 名: 指导教师: 完成 ...

最新文章

  1. 2018-04-29
  2. mysql登录抓包_MySQL登录验证的抓包
  3. node.js项目中常量的配置 - 个人文章 - SegmentFault 思否
  4. localhost 已拒绝连接_MySQL连接错误:Access denied for #x27;root#x27;@#x27;localhost#x27;
  5. JAVA JFrame编程
  6. 数据库语言 数据查询_使用这种简单的查询语言开始查询数据
  7. android novate乱码,Novate 一款Android RxStyle的网络框架
  8. 数据倾斜原理及解决方案
  9. 2020-11-11
  10. 数据保密-第三代透明加密技术
  11. Javashop 7.0 支付成功以后库里面没有记录问题
  12. 关于Generator expression must be parenthesized  out报错或者Error creating Django application: Error on pyt
  13. 如何进行大数据处理?大数据处理的方法步骤
  14. 旋度的散度恒为0公式推导
  15. 姆吉拉假面 时间不够怎么办_丰田如何指导我们基础设施的发展(并使我赞赏吉拉)...
  16. Building MFC application with /MD[d] (CRT dll version)requires MFC shared dll version~~~~
  17. 分享 10 个最常见的 JavaScript 问题
  18. Augmented Reality Law, Privacy, and Ethics
  19. App上架小米应用商店
  20. 2022中国科学技术大学计算机考研复试分数线是多少

热门文章

  1. antd权限管理_Antd Pro的权限组件
  2. 胡理辉:风电王国里的流程管控人
  3. ubuntu查看电脑配置信息
  4. oracle报1653解决办法,ORA-1653的问题
  5. pymysql操作MySQL数据库表-----爬虫豆瓣top250电影并存入数据库
  6. 编程算法 - 最好牛线(Best Cow Line) 代码(C)
  7. 华为手机wifi不显示连接到服务器,华为手机中无法连接WIFI处理方法
  8. 为村上隆直播做同传的火山翻译:成立仅3年,拿下5项世界冠军
  9. googleplay开发账号如何设置或更改帐号信息
  10. 引入Flutter module,执行flutter pub get提示:XXX using an older version of the Android plugin API