Python实现识别手写数字 Python图片读入与处理

写在前面

在上一篇文章Python徒手实现手写数字识别—大纲中,我们已经讲过了我们想要写的全部思路,所以我们不再说全部的思路。

我这一次将图片的读入与处理的代码写了一下,和大纲写的过程一样,这一段代码分为以下几个部分:

  • 读入图片;
  • 将图片读取为灰度值矩阵;
  • 图片背景去噪;
  • 切割图片,得到手写数字的最小矩阵;
  • 拉伸/压缩图片,得到标准大小为100x100大小矩阵;
  • 将图片拉为1x10000大小向量,存入训练矩阵中。

所以下面将会对这几个函数进行详解。

代码分析

基础内容

首先我们现在最前面定义基础变量

import os
from skimage import io
import numpy as np

##Essential vavriable 基础变量
#Standard size 标准大小
N = 100
#Gray threshold 灰度阈值
color = 100/255

其中标准大小指的是我们在最后经过切割、拉伸后得到的图片的尺寸为NxN。灰度阈值指的是在某个点上的灰度超过阈值后则变为1.

接下来是这图像处理的一部分的主函数

filenames = os.listdir(r"./num/")
pic = GetTrainPicture(filenames)

其中filenames得到在num目录下所有文件的名称组成的列表。pic则是通过函数GetTrainPicture得到所有训练图像向量的矩阵。这一篇文章主要就是围绕这个函数进行讲解。

GetTrainPicture函数

GetTrainPicture函数内容如下

#Read and save train picture 读取训练图片并保存
def GetTrainPicture(files):
 Picture = np.zeros([len(files), N**2+1])
 #loop all pictures 循环所有图片文件
 for i, item in enumerate(files):
  #Read the picture and turn RGB to grey 读取这个图片并转为灰度值
  img = io.imread('./num/'+item, as_grey = True)
  #Clear the noise 清除噪音
  img[img>color] = 1
  #Cut the picture and get the picture of handwritten number
  #将图片进行切割,得到有手写数字的的图像
  img = CutPicture(img)
  #Stretch the picture and get the standard size 100x100
  #将图片进行拉伸,得到标准大小100x100
  img = StretchPicture(img).reshape(N**2)
  #Save the picture to the matrix 将图片存入矩阵
  Picture[i, 0:N**2] = img
  #Save picture's name to the matrix 将图片的名字存入矩阵
  Picture[i, N**2] = float(item[0])
 return Picture

可以看出这个函数的信息量非常大,基本上今天做的所有步骤我都把封装到一个个函数里面了,所以这里我们可以看到图片处理的所有步骤都在这里。

提前准备

首先是创建了一个用来存放所有图像向量的矩阵Picture,大小为fx10001,其中f代表我们拥有的训练图片的数目,10001的前10000位代表图片展开后的向量长度,最后一维代表这一个向量的类别,比如说时2就代表这个图片上面写的数字是2.

接下来用的是一个for循环,将files里面每一个图片进行一次迭代,计算出向量后存入picture。

在循环中的内容就是对每一张图片进行的操作。

读入图片并清除背景噪音

首先是io.imread函数,这个函数是将图片导出成为灰度值的矩阵,每一个像素点是矩阵上的一个元素。

接下来是img[img>color]=1这一句。这一句运用了逻辑运算的技巧,我们可以将其分为两部分

point = img > color
img[point] = 1

首先是img>color,img是一个矩阵,color是一个数。意义就是对img中所有元素进行判断是否大于color这个数,并输出一个与img同等大小的矩阵,对应元素上是该值与color判断后的结果,有False与True。如果大于这个数,那么就是Ture,否则是False。下面举个例子,不再赘述。

a = np.array([1, 2, 3, 4])
print(a>2)

#以下为输出结果
[False False True True]

之后的img[point] = 1说明将所有True的值等于1。举个例子

a = np.array([1, 2, 3, 4])
p = a > 2
a[p] = 0
print(a)

#以下为输出结果
[1 2 0 0]

因此我通过这样的方法来清除掉了与数字颜色差别太大的背景噪音。

切割图像

首先切割图像的函数我写的是CutPicture。我们来说一下这个切割图像的意思。比如说有一个人写字写的特别小,另一个人写字写的特别大。就像是下图所示,所以我们进行这样的操作。沿着图片的边进行切割,得到了下面切割后的图片,让数字占满整个图片,从而具有可比性。

所以下面贴出代码,详细解释一下我是怎么做的。

#Cut the Picture 切割图象
def CutPicture(img):
 #初始化新大小
 size = []
 #图片的行数
 length = len(img)
 #图片的列数
 width = len(img[0,:])
 #计算新大小
 size.append(JudgeEdge(img, length, 0, [-1, -1]))
 size.append(JudgeEdge(img, width, 1, [-1, -1]))
 size = np.array(size).reshape(4)
 print(size)
 return img[size[0]:size[1]+1, size[2]:size[3]+1]

首先函数导入过来的的参数只有一个原img。

我第一步做的是把新的大小初始化一下,size一共会放入四个值,第一个值代表原图片上的手写数字图案的最高行,第二个值代表的是最低行,第三个值代表数字图案的最左列,,第四个只代表最右列**。这个还看不明白的话就看上面的图示,就是沿着图片切割一下就好了。

接下来的length和width分别代表着原图片的行数与列数,作用在下面。我又创建了一个JudgeEdge函数,这个函数是输出它的行数或者列数的两位数字。第一个append是给size列表放入了两个行序号(最高行和最低行),第二个append是给size放进两个列序号(最左列和最右列)。所以接下来就看JudgeEdge函数是干什么的。

def JudgeEdge(img, length, flag, size):
 for i in range(length):
  #Cow or Column 判断是行是列
  if flag == 0:
   #Positive sequence 正序判断该行是否有手写数字
   line1 = img[img[i,:]<color]
   #Negative sequence 倒序判断该行是否有手写数字
   line2 = img[img[length-1-i,:]<color]
  else:
   line1 = img[img[:,i]<color]
   line2 = img[img[:,length-1-i]<color]
  #If edge, recode serial number 若有手写数字,即到达边界,记录下行
  if len(line1)>=1 and size[0]==-1:
   size[0] = i
  if len(line2)>=1 and size[1]==-1:
   size[1] = length-1-i
  #If get the both of edge, break 若上下边界都得到,则跳出
  if size[0]!=-1 and size[1]!=-1:
   break
 return size

JudgeEdge函数的参数flag就是用来判断是行还是列,当flag=0时,说明以行为基础开始循环;当flag=1时说明以列为基础进行循环。所以参数length传递的时候就是行数和列数。接下来的for循环就是根据length的大小看似是循环。

当是行时,我这里用line1和line2起到的是一个指针的作用,即在第i行时,line1的内容就是这一行拥有非白色底(数值为1)的像素的个数;line2的作用则是反序的,也就是他计算的是倒数i行非白色像素个数,这样做的目的是能够快一点,让上下同时开始进行寻找,而不用line1把整个图片循环一遍,line2把整个图片循环一遍,大大节省了时间。

寻找这一行拥有非白色底的像素的个数这一个语句同样的运用了逻辑判断,和上文中去噪的原理一模一样。

当line里面有数的时候,说明已经到达了手写数字的边缘。这时候就记录下来,然后就不再改变。当两个line都不等于初始值-1时,说明已经找到了两个边缘,这时候就可以跳出循环并且return了。

这个函数就是这样。所以说切割图像的完整代码就是这样子,下面就要把切割的大小不一的图像给拉伸成标准大小100x100了。

拉伸图像

因为切割以后的图像有大有小,一张图片的大小可能是21x39(比如说数字2),另一张可能是4x40(比如说数字1)。所以为了能够让他们统一大小称为100x100,我们就要把他们拉伸一下。

大概就是像图上的一样。实际情况的图案可能会更复杂,所以我们下面展示一下代码

#Stretch the Picture 拉伸图像
def StretchPicture(img):
 newImg = np.ones(N**2).reshape(N, N)
 ##Stretch/Compress each cows/columns 对每一行/列进行拉伸/压缩
 #The length of each cows after stretching 每一行拉伸/压缩的步长
 step1 = len(img[0])/100
 #Each columns blabla 每一列拉伸/压缩的步长
 step2 = len(img)/100
 #Operate on each cows 对每一行进行操作
 for i in range(len(img)):
  for j in range(N):
   newImg[i, j] = img[i, int(np.floor(j*step1))]
 #Operate on each columns 对每一列进行操作
 for i in range(len(img[0])):
  for j in range(N):
   newImg[j, i] = img[int(np.floor(j*step2)), i]
 return newImg

首先初始化一个新的图片矩阵,这个大小就是标准大小100x100。接下来才是重头戏。我这里用的方法是比较简单基础的方法,但是可能依旧比较难。

首先定义两个步长step1和step2,分别代表拉伸/压缩行与列时的步长。这里的原理就是把原来的长度给他平均分成100份,然后将这100个像素点分别对应上原本的像素点。

如下图所示,图像1我们假设为原图像,图像2我们假设为标准图像,我们需要把图像1转化为图像2,其中每一个点代表一个像素点,也就是图像1有五个像素点,图像2有四个像素点。

所以我的思想就是直接让图像2的像素点的值等于距离它最近的图像1的像素点。

我们为了方便起见,在这里定义一个语法:图像2第三个数据点我们可以写为2_3.

所以2_1对应的就是1_1,2_2对应的就是1_2,2_3对应的是1_4,2_4对应的是1_5。就这样我们就能够得到了图像2所有的数据点。

利用数学的形式表现出来,就是假设图像1长度为l_1,图像2长度为l_2,所以令图像2的步长为l_1/l_2,也就是说当图像2的第一个像素点对应图像1第一个像素点,图像2的最后一个像素点对应图像1最后一个像素点。然后图像2第二个像素点位置就是2*l_1/l_2,对应图像1第floor(2*l_1/l_2)个像素点。以此类推就行。因此再回头看一下那一段代码,这一段是不是就好理解了?

之后对行与列分别进行这个操作,所以就可以得到标准的图片大小。然后再返回到GetTrainPicture即可。

再GetTrainPicture函数中,我用了reshape函数把原本100x100大小的图片拉伸成为1x10000大小的向量,然后存入矩阵当中,并将这一张图片的类别存入矩阵最后一个。

以上就是图片处理的所有内容。

小结

以上就是把一张图片经过处理后存入矩阵的内容。

本文中的所有算法、代码均是我自己构思的,所以可能存在一些不足之处,我没有系统的学习过图像的相关知识,也并不是计算机专业,因此可能在理论上有一些不合乎情况,所以如果有错误的话欢迎一起讨论,谢谢。

您可能感兴趣的文章:

  • Python实现识别手写数字大纲
  • python实现识别手写数字 python图像识别算法
  • python实现图像识别功能
  • 学习Python3 Dlib19.7进行人脸面部识别
  • Python3结合Dlib实现人脸识别和剪切
  • 用Python进行简单图像识别(验证码)
  • Python3一行代码实现图片文字识别的示例
  • Python用sndhdr模块识别音频格式详解
  • Python用imghdr模块识别图片格式实例解析
  • Python实现识别手写数字 简易图片存储管理系统
(0)

相关推荐

  • Python实现识别手写数字 简易图片存储管理系统

    写在前面 上一篇文章Python实现识别手写数字-图像的处理中我们讲了图片的处理,将图片经过剪裁,拉伸等操作以后将每一个图片变成了1x10000大小的向量.但是如果只是这样的话,我们每一次运行的时候都需要将他们计算一遍,当图片特别多的时候会消耗大量的时间. 所以我们需要将这些向量存入一个文件当中,每次先看看图库中有没有新增的图片,如果有新增的图片,那么就将新增的图片变成1x10000向量再存入文件之中,然后从文件中读取全部图片向量即可.当图库中没有新增图片的时候,那么就直接调用文件中的图片向量进

  • python实现识别手写数字 python图像识别算法

    写在前面 这一段的内容可以说是最难的一部分之一了,因为是识别图像,所以涉及到的算法会相比之前的来说比较困难,所以我尽量会讲得清楚一点. 而且因为在编写的过程中,把前面的一些逻辑也修改了一些,将其变得更完善了,所以一切以本篇的为准.当然,如果想要直接看代码,代码全部放在我的GitHub中,所以这篇文章主要负责讲解,如需代码请自行前往GitHub. 本次大纲 上一次写到了数据库的建立,我们能够实时的将更新的训练图片存入CSV文件中.所以这次继续往下走,该轮到识别图片的内容了. 首先我们需要从文件夹中

  • Python用imghdr模块识别图片格式实例解析

    imghdr模块 功能描述:imghdr模块用于识别图片的格式.它通过检测文件的前几个字节,从而判断图片的格式. 唯一一个API imghdr.what(file, h=None) 第一个参数file可以是用rb模式打开的file对象或者表示路径的字符串和PathLike对象.h参数是一段字节串.函数返回表示图片格式的字符串. >>> import imghdr >>> imghdr.what('test.jpg') 'jpeg' 具体的返回值和描述如下: 返回值 描述

  • 学习Python3 Dlib19.7进行人脸面部识别

    0.引言 自己在下载dlib官网给的example代码时,一开始不知道怎么使用,在一番摸索之后弄明白怎么使用了: 现分享下 face_detector.py 和 face_landmark_detection.py 这两个py的使用方法: 1.简介 python: 3.6.3 dlib: 19.7 利用dlib的特征提取器,进行人脸 矩形框 的特征提取: dets = dlib.get_frontal_face_detector(img) 利用dlib的68点特征预测器,进行人脸 68点 特征提

  • Python3一行代码实现图片文字识别的示例

    自学Python3第5天,今天突发奇想,想用Python识别图片里的文字.没想到Python实现图片文字识别这么简单,只需要一行代码就能搞定 from PIL import Image import pytesseract #上面都是导包,只需要下面这一行就能实现图片文字识别 text=pytesseract.image_to_string(Image.open('denggao.jpeg'),lang='chi_sim') print(text) 我们以识别诗词为例 下面是我们要识别的图片 先

  • Python实现识别手写数字大纲

    写在前面 其实我之前写过一个简单的识别手写数字的程序,但是因为逻辑比较简单,而且要求比较严苛,是在50x50大小像素的白底图上手写黑色数字,并且给的训练材料也不够多,导致准确率只能五五开.所以这一次准备写一个加强升级版的,借此来提升我对Python处理文件与图片的能力. 这次准备加强难度: 被识别图片可以是任意大小: 不一定是白底图,只要数字颜色是黑色,周围环境是浅色就行: 加强识别手写数字的逻辑,提升准确率. 因为我还没开始正式写,并且最近专业课程学习也比较紧迫,所以可能更新的比较慢.不过放心

  • python实现图像识别功能

    本文实例为大家分享了python实现图像识别的具体代码,供大家参考,具体内容如下 #! /usr/bin/env python from PIL import Image import pytesseract url='img/denggao.jpeg' image=Image.open(url) #image=image.convert('RGB') # RGB image=image.convert('L') # 灰度 image.load() text=pytesseract.image_

  • Python3结合Dlib实现人脸识别和剪切

    0.引言 利用python开发,借助Dlib库进行人脸识别,然后将检测到的人脸剪切下来,依次排序显示在新的图像上: 实现的效果如下图所示,将图1原图中的6张人脸检测出来,然后剪切下来,在图像窗口中依次输出显示人脸: 实现比较简单,代码量也比较少,适合入门或者兴趣学习. 图1 原图和处理后得到的图像窗口 1.开发环境 python: 3.6.3 dlib: 19.7 OpenCv, numpy import dlib # 人脸识别的库dlib import numpy as np # 数据处理的库

  • 用Python进行简单图像识别(验证码)

    这是一个最简单的图像识别,将图片加载后直接利用Python的一个识别引擎进行识别 将图片中的数字通过 pytesseract.image_to_string(image)识别后将结果存入到本地的txt文件中 #-*-encoding:utf-8-*- import pytesseract from PIL import Image class GetImageDate(object): def m(self): image = Image.open(u"C:\\a.png") text

  • Python用sndhdr模块识别音频格式详解

    本文主要介绍了Python编程中,用sndhdr模块识别音频格式的相关内容,具体如下. sndhdr模块 功能描述:sndhdr模块提供检测音频类型的接口. 唯一一个API sndhdr模块提供了sndhdr.what(filename)和sndhdr.whathdr(filename)两个函数.但实际上它们的功能是一样的.(不知道多写一个的意义何在,what函数在内部调用了whathdr函数并把数据完完整整地返回) 在之前的版本,whathdr函数返回元组类型的数据,在Python3.5版本之

随机推荐