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 识别. 由于公司业务需要,需要开发一个客户端程序 ...
随机推荐
- Hibernate打印SQL及附加参数
今天在项目运行过程中,一直报一个org.hibernate.exception.GenericJDBCException: could not insert 异常,Root Cause是IBM DB ...
- ORM-Dapper学习<一>
ORM 框架简介 对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的.面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关 ...
- ORM-Dapper学习<二>
Dapper的简介 Dapper是.NET下一个micro的ORM,它和Entity Framework或Nhibnate不同,属于轻量级的,并且是半自动的.Dapper只有一个代码文件,完全开源,你 ...
- Android -- 仿小红书欢迎界面
1,觉得小红书的欢迎界面感觉很漂亮,就像来学习学习一下来实现类似于这种效果 原效果图如下: 2,根据效果我们来一点点分析 第一步:首先看一下我们的主界面布局文件视图效果如下: main_activi ...
- spring循环依赖问题分析
新搞了一个单点登录的项目,用的cas,要把源码的cas-webapp改造成适合我们业务场景的项目,于是新加了一些spring的配置文件. 但是在项目启动时报错了,错误日志如下: 一月 , :: 下午 ...
- 手动编写JQUERY插件
就拿一个简单的示例来说,鼠标点击输入框,提示文字消息,鼠标移开,再显示提示文字. <script type="text/javascript"> //编写插件 (fun ...
- box-shadow IE8兼容处理
根据canisue(http://caniuse.com/#search=box-shadow),box-shadow兼容性如下图所示: 测试代码: <!DOCTYPE html> < ...
- 通过composer管理工具安装laravel
当安装好composer管理工具后,将composer的bin目录添加至环境变量中(PATH),方便在任意目录下执行composer命令. 方法1:我们通过laravel工具安装laravel 首先, ...
- iOSiOS开发之退出功能(易错)
如果,我们有两个控制器,第一个控制器是MainController,它是与Main.storyboard相关联的.第二个控制器是myController.假设myController中有一个退出按钮, ...
- 27. Remove Element - 移除元素-Easy
Description: Given an array and a value, remove all instances of that value in place and return the ...