专栏名称: 编程派
Python程序员都在看的公众号,跟着编程派一起学习Python,看最新国外教程和资源!
目录
相关文章推荐
Python爱好者社区  ·  刚刚,GPT-4.5震撼上线情商逆天!Ope ... ·  3 天前  
Python爱好者社区  ·  我???这就是信息差吗?F12改成绩,19. ... ·  15 小时前  
Python爱好者社区  ·  两天私活,5w到手 ·  昨天  
Python爱好者社区  ·  AI ... ·  15 小时前  
Python爱好者社区  ·  王炸!DeepSeek彻底爆了! ·  3 天前  
51好读  ›  专栏  ›  编程派

【Python破解九宫格数独】:knn 数字识别

编程派  · 公众号  · Python  · 2017-04-18 11:46

正文

作者:冰不语

来源:公众号「CVPy」

前言

首先需要说明, 这里所说的数字识别不是手写数字识别!

但凡对机器学习有所了解的人,相信看到数字识别的第一反应就是MNIST。MNIST是可以进行数字识别,但是那是手写数字。我们现在要做的是要识别从九宫格图片中提取出来的印刷体的数字。手写数字集训练出来的模型用来识别印刷体数字,显然不太专业。而且手写体跟印刷体相差不小,我们最看重的正确率问题不能保证。

本文从零开始做一遍数字识别,展示了数字识别的完整流程。从收集数据开始,到数据预处理,再到训练KNN,最后进行数字识别。

我们一步一步来说。

数据收集

为了便于处理,我百度找到了10张下面这样按照1-9-0顺序排列的图片,作为我们的初始数据集。

有的图片可能本来除数字区域外,周围空白部分比较多。为了便于处理,首先用windows自带的画图软件把图片裁剪成上面这样只包含数字区域的样子。

这十张数据集基本涵盖了印刷数字体的不同样式、字体,而且颜色、背景甚至渐变方式都各不相同。

数据处理

显然,我们第一步要做的就是上一节的内容,那就是把图片中的数字分别提取出来。

训练knn,还有其他任何有监督的机器学习模型,不光要有样本数据,还要有知道每一个样本对应的标签。这也是为什么我要选择上面这样按顺序排列的数字图片。

提取数字之后,我们可以对每一个数字的位置进行排序,然后根据位置信息可以知道每一个数字是几。标签也就由此生成了。

这一部分的内容可以分两部分来说,第一部分就是提取数字,第二部分是提取数字之后的数据预处理。

1.提取数字

提取数字的处理流程与上一篇内容差不多:

1.遍历文件夹下的原始数字图片;

2.对每一张图片进行轮廓提取操作,只提取外围轮廓(参考上一节讲解);

  1. img_path = gb.glob("numbers\\*")

  2. k = 0

  3. labels = []

  4. samples =  []

  5. for path in img_path:

  6.    img  = cv2.imread(path)      

  7.    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

  8.    blur = cv2.GaussianBlur(gray,(5,5),0)

  9.    thresh = cv2.adaptiveThreshold(blur,255,1,1,11,2)    

  10.    image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

3.求轮廓外包矩形,并根据矩形大小信息筛选出所有的数字轮廓;

4.然后根据位置信息对数字框排序,显然第一排依次是12345,第二排依次是67890;

  1.    height,width = img.shape[:2]

  2.    w = width/5

  3.    rect_list = []

  4.    list1 = []

  5.    list2 = []

  6.    for cnt in contours:

  7.        #if cv2.contourArea(cnt)>100:

  8.        [x,y,w,h] = cv2.boundingRect(cnt )

  9.        if w>30 and h > (height/4):        

  10.            if y < (height/2):

  11.                list1.append([x,y,w,h])

  12.            else:

  13.                list2.append([x,y,w,h])

  14.    list1_sorted = sorted(list1,key = lambda t : t[0])

  15.    list2_sorted = sorted(list2,key = lambda t : t[0])

5.提取出每一个数字所在的矩形框,作为ROI取出。

  1.     for i in range(5):

  2.        [x1,y1,w1,h1] = list1_sorted[i]

  3.        [x2,y2,w2,h2] = list2_sorted[i]                

  4.        number_roi1 = gray[y1:y1+h1, x1:x1+w1] #Cut the frame to size

  5.        number_roi2 = gray[y2:y2+h2, x2:x2+w2] #Cut the frame to size  

数据预处理

为了加快训练速度,我们不用原图作为输入,而是对每一个数字原图做一定的处理。此处可选方案很多,提取特征有很多经典特征可选,也可以是自己设计的特征。

这里我用比较简单的方法,把每一张数字图片ROI转换为二值图像。大致流程是这样的:

1.把每一张ROI大小统一变换为40 x 20。

2.阈值分割。

  1.        resized_roi1=cv2.resize(number_roi1,(20,40))

  2.        thresh1 = cv2.adaptiveThreshold(resized_roi1,255,1,1,11,2)

  3.        resized_roi2=cv2.resize(number_roi2,(20,40))

  4.        thresh2 = cv2.adaptiveThreshold(resized_roi2,255,1,1,11,2)

3.把二值图像转换为0-1二值图像。

4.把处理完的数字图片保存到对应数字的文件夹中。(此为中间过程,可注释掉)

  1.        number_path1 = "number\\%s\\%d" % (str(i+1),k) + '.jpg'

  2.        j = i+6

  3.        if j ==10:

  4.            j = 0

  5.        number_path2 = "number\\%s\\%d" % (str(j),k) + '.jpg'

  6.        k+=1

  7.        normalized_roi1 = thresh1/255.

  8.        normalized_roi2 = thresh2/255.

  9.        cv2.imwrite(number_path1,thresh1)

  10.        cv2.imwrite(number_path2,thresh2)

处理完之后保存的文件夹如下:

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

5.把处理完的二值图像展开成一行。

6.最后把展开成的一行行样本保存起来作为训练用的数据。

7.对应的,把数字标签按照数字的保存顺序对应保存成训练用的数据。

  1.        sample1 = normalized_roi1.reshape((1,800))

  2.        samples.append(sample1[0])

  3.        labels.append(float(i+1))

  4.        sample2 = normalized_roi2.reshape((1,800))

  5.        samples.append(sample2[0])

  6.        labels.append(float(j))

  1. import numpy as np

  2. samples = np.array(samples,np.float32)

  3. labels







请到「今天看啥」查看全文