OpenCV 玩九宫格数独(二):knn 数字识别
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~
作者:刘潇龙
前言
首先需要说明,这里所说的数字识别不是手写数字识别!
但凡对机器学习有所了解的人,相信看到数字识别的第一反应就是MNIST。MNIST是可以进行数字识别,但是那是手写数字。我们现在要做的是要识别从九宫格图片中提取出来的印刷体的数字。手写数字集训练出来的模型用来识别印刷体数字,显然不太专业。而且手写体跟印刷体相差不小,我们最看重的正确率问题不能保证。
本文从零开始做一遍数字识别,展示了数字识别的完整流程。从收集数据开始,到数据预处理,再到训练KNN,最后进行数字识别。
我们一步一步来说。
数据收集
为了便于处理,我百度找到了10张下面这样按照1-9-0顺序排列的图片,作为我们的初始数据集。

有的图片可能本来除数字区域外,周围空白部分比较多。为了便于处理,首先用windows自带的画图软件把图片裁剪成上面这样只包含数字区域的样子。
这十张数据集基本涵盖了印刷数字体的不同样式、字体,而且颜色、背景甚至渐变方式都各不相同。
数据处理
显然,我们第一步要做的就是上一节的内容,那就是把图片中的数字分别提取出来。
训练knn,还有其他任何有监督的机器学习模型,不光要有样本数据,还要有知道每一个样本对应的标签。这也是为什么我要选择上面这样按顺序排列的数字图片。
提取数字之后,我们可以对每一个数字的位置进行排序,然后根据位置信息可以知道每一个数字是几。标签也就由此生成了。
这一部分的内容可以分两部分来说,第一部分就是提取数字,第二部分是提取数字之后的数据预处理。
1.提取数字
提取数字的处理流程与上一篇内容差不多:
1.遍历文件夹下的原始数字图片;
2.对每一张图片进行轮廓提取操作,只提取外围轮廓(参考上一节讲解);
img_path = gb.glob("numbers\\*")
k =
labels = []
samples = []
for path in img_path:
img = cv2.imread(path)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(,),)
thresh = cv2.adaptiveThreshold(blur,,,,,)
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
3.求轮廓外包矩形,并根据矩形大小信息筛选出所有的数字轮廓;
4.然后根据位置信息对数字框排序,显然第一排依次是12345,第二排依次是67890;
height,width = img.shape[:]
w = width/
rect_list = []
list1 = []
list2 = []
for cnt in contours:
#if cv2.contourArea(cnt)>100:
[x,y,w,h] = cv2.boundingRect(cnt) if w> and h > (height/):
if y < (height/):
list1.append([x,y,w,h])
else:
list2.append([x,y,w,h])
list1_sorted = sorted(list1,key = lambda t : t[])
list2_sorted = sorted(list2,key = lambda t : t[])
5.提取出每一个数字所在的矩形框,作为ROI取出。
for i in range():
[x1,y1,w1,h1] = list1_sorted[i]
[x2,y2,w2,h2] = list2_sorted[i]
number_roi1 = gray[y1:y1+h1, x1:x1+w1] #Cut the frame to size
number_roi2 = gray[y2:y2+h2, x2:x2+w2] #Cut the frame to size
数据预处理
为了加快训练速度,我们不用原图作为输入,而是对每一个数字原图做一定的处理。此处可选方案很多,提取特征有很多经典特征可选,也可以是自己设计的特征。
这里我用比较简单的方法,把每一张数字图片ROI转换为二值图像。大致流程是这样的:
1.把每一张ROI大小统一变换为40 x 20。
2.阈值分割。
resized_roi1=cv2.resize(number_roi1,(,))
thresh1 = cv2.adaptiveThreshold(resized_roi1,,,,,) resized_roi2=cv2.resize(number_roi2,(,))
thresh2 = cv2.adaptiveThreshold(resized_roi2,,,,,)
3.把二值图像转换为0-1二值图像。
4.把处理完的数字图片保存到对应数字的文件夹中。(此为中间过程,可注释掉)
number_path1 = "number\\%s\\%d" % (str(i+),k) + '.jpg'
j = i+
if j ==:
j =
number_path2 = "number\\%s\\%d" % (str(j),k) + '.jpg'
k+= normalized_roi1 = thresh1/.
normalized_roi2 = thresh2/.
cv2.imwrite(number_path1,thresh1)
cv2.imwrite(number_path2,thresh2)
处理完之后保存的文件夹如下:

每一个文件夹里面类似这样,可以看到背景有黑有白,数字也是有黑有白:

5.把处理完的二值图像展开成一行。
6.最后把展开成的一行行样本保存起来作为训练用的数据。
7.对应的,把数字标签按照数字的保存顺序对应保存成训练用的数据。
sample1 = normalized_roi1.reshape((,))
samples.append(sample1[])
labels.append(float(i+)) sample2 = normalized_roi2.reshape((,))
samples.append(sample2[])
labels.append(float(j))
import numpy as np
samples = np.array(samples,np.float32)
labels = np.array(labels,np.float32)
labels = labels.reshape((labels.size,))
np.save('samples.npy',samples)
np.save('label.npy',labels)
训练kNN识别数字
这里用opencv自带的knn算法实现。我同时尝试了opencv自带的神经网络和SVM,发现还是kNN的效果最好。有兴趣的可以自己去尝试一下。也可能是我参数没调好。
这里的流程是:
1.加载上面保存的样本和标签数据;
2.分别用80个作为训练数据,20个作为测试数据;
3.用opencv自带的knn训练模型;
4.用训练好的模型识别测试数据中的数字;
5.输出预测值和实际标签值。
import numpy as np
import cv2 samples = np.load('samples.npy')
labels = np.load('label.npy') k =
train_label = labels[:k]
train_input = samples[:k]
test_input = samples[k:]
test_label = labels[k:] model = cv2.ml.KNearest_create()
model.train(train_input,cv2.ml.ROW_SAMPLE,train_label) retval, results, neigh_resp, dists = model.findNearest(test_input, )
string = results.ravel() print(test_label.reshape(,len(test_label))[])
print(string)
下面是输出结果:

可以看到,预测值和实际值简直一模一样!
注意
1.opencv中的knn只能训练模型,不能保存和加载模型。所以只能用的时候训练,训练好直接用。
2.此次训练样本只有不到一百,暂时只能保证对于本系列文章自带的九宫格图片进行完美的数字识别。其他图片的数字识别准确率不敢保证。如果想要得到更好的效果,请按照机器学习的方法进行优化,或进行更好的数据与处理,或加大数据集等。
3.整个项目代码会在下一篇,也就是最终篇之后放出。
相关推荐:
OpenCV玩九宫格数独(一):九宫格图片中提取数字
OpenCV检测篇(一)——猫脸检测
OpenCV检测篇(二)——笑脸检测
此文已由作者授权腾讯云技术社区发布,转载请注明文章出处
原文链接:https://www.qcloud.com/community/article/901168
获取更多腾讯海量技术实践干货,欢迎大家前往腾讯云技术社区
OpenCV 玩九宫格数独(二):knn 数字识别的更多相关文章
- knn 数字识别
#knn介绍 更多参考百度介绍 算法思想:给定一个带标检的训练数据集(就是带分类结果的样本),对于一个新的输入实例,我们在训练数据集中以某种距离度量方式找出与该输入实例距离最近邻的k个实例.找出这k个 ...
- 手把手教你使用LabVIEW OpenCV DNN实现手写数字识别(含源码)
@ 目录 前言 一.OpenCV DNN模块 1.OpenCV DNN简介 2.LabVIEW中DNN模块函数 二.TensorFlow pb文件的生成和调用 1.TensorFlow2 Keras模 ...
- opencv 视觉项目学习笔记(二): 基于 svm 和 knn 车牌识别
车牌识别的属于常见的 模式识别 ,其基本流程为下面三个步骤: 1) 分割: 检测并检测图像中感兴趣区域: 2)特征提取: 对字符图像集中的每个部分进行提取: 3)分类: 判断图像快是不是车牌或者 每个 ...
- 基于OpenCV的KNN算法实现手写数字识别
基于OpenCV的KNN算法实现手写数字识别 一.数据预处理 # 导入所需模块 import cv2 import numpy as np import matplotlib.pyplot as pl ...
- 机器学习(二)-kNN手写数字识别
一.kNN算法是机器学习的入门算法,其中不涉及训练,主要思想是计算待测点和参照点的距离,选取距离较近的参照点的类别作为待测点的的类别. 1,距离可以是欧式距离,夹角余弦距离等等. 2,k值不能选择太大 ...
- Java基于opencv实现图像数字识别(三)—灰度化和二值化
Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...
- Java基于opencv实现图像数字识别(二)—基本流程
Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要 ...
- 一看就懂的K近邻算法(KNN),K-D树,并实现手写数字识别!
1. 什么是KNN 1.1 KNN的通俗解释 何谓K近邻算法,即K-Nearest Neighbor algorithm,简称KNN算法,单从名字来猜想,可以简单粗暴的认为是:K个最近的邻居,当K=1 ...
- opencv +数字识别
现在很多场景需要使用的数字识别,比如银行卡识别,以及车牌识别等,在AI领域有很多图像识别算法,大多是居于opencv 或者谷歌开源的tesseract 识别. 由于公司业务需要,需要开发一个客户端程序 ...
随机推荐
- 1664: [Usaco2006 Open]County Fair Events 参加节日庆祝
1664: [Usaco2006 Open]County Fair Events 参加节日庆祝 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 255 S ...
- JavaScript 再认识(一):Function调用模式对this的影响
近来,学习了一下<JavaScript精粹>,读到了函数这章,理清了JavaScript中this在不同调用模式下的指向. 1.Function调用模式:Function是JavaScri ...
- rsync+inotify脚本
#!/bin/bash src=/data/ # 需要同步的源路径 des=data ...
- 如何用photoshop把一张图片分割成几张图片呢?
今天情人节,祝大家节日快乐!朋友发来一张照片,我发现这张照片是几张照片组合起来的,是不是感觉每一张都是萌萌哒呢?为了体现单张的独特性,现在我要把它切分成单张,使用Photoshop CS5该怎么弄呢? ...
- flex中为控件添加监听器并计算
1.添加监听器: public function moduleCreationComplete():void { this.D601_29a.addEventListener(FlexEvent.SE ...
- 我的日志文件java logger
操作读取日志文件, 1.使用默认的日志文件,并验证默认级别 public void originalConfig() { Logger logger = Logger.getLogger(Logger ...
- win32 htmlayout点击按钮创建新窗口,以及按钮图片样式
最近在做一个C++ win32的桌面图形程序,我不是C++程序员,做这个只是因为最近没什么java的活. windows api,之前接触的时候,还是大学,那时用这个开发打飞机游戏纯粹是娱乐.现在基本 ...
- firefox无法使用yslow的解决方案
首先,Yslow不支持firefox 36及以上版本. 解决方案:使用yslow的书签版本 使用方法:1.访问这里 http://yslow.org/mobile/ 2.把页面最后的那个 Deskto ...
- 《HelloGitHub》第12期
<HelloGitHub>第12期 兴趣是最好的老师,<HelloGitHub>就是帮你找到兴趣! 简介 最开始我只是想把自己在浏览 GitHub 过程中,发现的有意思.高质量 ...
- 按条件生成j随机json包:randomjson
前端开发中,在做前后端分离的时候,经常需要手写json数据,有2个问题特别揪心: 1,数据是写死的,不能按一定的条件随机生成长度不一,内容不一的数据 2,写数组的时候,如果有很多条,需要一条一条地写, ...