话说上篇说到是预处理图片不给力引起的问题,本篇调整方向探索。

预处理图片:

  1. 之前处理的图片是二值化了,就算是把切割偏移排除在外,切割出来的数字点阵不一。 之前的方法:im.convert(‘1’)太简单暴力了 改进后的方法:

def two_convert(im, threshold): #给定阈值,返回二值图像
Lim = im.convert('L')
table = []
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(255)
#table.append(1)
# convert to binary image by the table
bim = Lim.point(table, '1')
return bim
im = two_convert(im,180)

使用新方法之后,该清晰的加强清晰了,该淡化的也淡化了,it works!

  1. 切割单组图片 之前判断有多少组数字的函数依然可用,现在主要是改变切割每组数字和切割单个数字的方法,最终的目的是每个单个数字都不留白边。

切割每组数字的方法,参考下面代码片段和注释: def splitdigits(im,num): char_width = 55 + 2#每个字符宽5,最多有5个字符,再给2个像素的冗余 white = 255 black = 0 w, h = im.size data = list(im.getdata()) emptywidth = (w - numchar_width) / num - 10#减掉10,留点冗余

x,y = 0,0 loop = 0 whitenum = 0

#从左向右枚举 while x < w: y = 0 while y < h: #当遇到第一个黑点,就切割,同时修改x if data[y*w +x] == black: x2 = x+char_width if x2 > w: x2 = w#避免越界 box = (x,0,x2,h)#确定切割范围 newim = im.crop(box)#切割单组数字 getsingle(newim)#切割识别单组数字 loop += 1 if loop >= num: return x += char_width + emptywidth#加大步长,加快收缩范围枚举 break else: y += 1 x += 1

  1. 切割单个数字 顶部坐标和高度是固定的、切割目标:左右边界都没有白边,如果有白边则认为是另外字符。

切割每个单独数字的方法,参考下面代码片段和注释: def getsingle(im): w, h = im.size data = list(im.getdata()) rec = []#用来记录数组的从左向右的断连情况 lt = 0#每个字符的左边界 numstr = ’’ for x in xrange(w): s=0 for y in xrange(h): if data[y*w +x] == 0: s += 1 rec.append(s)

if s == 0 or x == w-1:#如果遇到一个空白 if rec[x-1] > 0:#如果前一列不是空白,那就可以切割了 box = (lt,0,x,h)#切割单个字符 newim = im.crop(box) numstr = ‘%s%s’ % (numstr,ocrsingle(newim,rec[lt:x]))#识别单个字符 elif x > 0 and rec[x-1] == 0:#如果遇到的列是有黑点的,并且前一列是空白,那这个就是lt lt = x #重新计算切割的左边界 print numstr

  1. 字模提取 在切割单个字符中,有一个办法(这句话是帅帅看喜羊羊后的口头禅之一)。 思路:在上面代码的rec中,记录了每个字符的的每一列包含的黑点个数,这些数据基本就可以用来做匹配了。

在处理了几张图后,采集到的数据如下: dot = [1] num0 = [6, 2, 2, 3, 2] num0a = [6, 2, 2, 4, 1] num0b = [6, 2, 2, 4, 2] num1 = [1, 1, 8] num1a = [1, 8] num2 = [2, 3, 3, 4] num2a = [2, 3, 3, 4, 1] num3 = [2, 3, 4, 5] num3a = [1, 3, 4, 6] num4 = [1, 3, 2, 3, 8, 1] num4a = [1, 3, 2, 2, 8, 1] num4b = [1, 2, 2, 2, 8, 1] num5 = [5, 3, 3, 4] num6 = [6, 3, 3, 4, 1] num6a = [6, 3, 3, 4] num6b = [6, 2, 3, 5, 1] num7 = [1, 3, 4, 3] num7a = [1, 3, 3, 4, 1] num7b = [1, 3, 3, 3] num8 = [6, 3, 3, 4, 1] num8a = [6, 4, 4, 6] num8b = [5, 3, 3, 6] num9 = [4, 3, 3, 5, 2] num9a = [5, 3, 3, 6, 1] num9b = [5, 3, 3, 6]

发现8和9有重合的,于是又采集了字符从上到下每一行黑点的个数列表。 8和9的区别在于倒数第二行和倒数第三行的黑点个数,9是1个,8是2个。 dot_h = [0, 0, 0, 0, 0, 0, 0, 1] num0_h = [2, 2, 1, 2, 2, 1, 2, 3] #num0_hb = [3, 2, 1, 2, 2, 1, 2, 3] num1_h = [1, 3, 1, 1, 1, 1, 1, 1] num2_h = [2, 1, 1, 1, 1, 1, 1, 4] #num2_ha = [2, 1, 1, 1, 1, 1, 1, 5] num3_h = [3, 1, 1, 2, 2, 1, 1, 3] #num3_ha = [2, 1, 1, 2, 2, 1, 1, 4] num4_h = [2, 2, 2, 2, 2, 6, 1, 1] #num4_ha = [1, 2, 2, 1, 2, 6, 1, 1] num5_h = [4, 1, 1, 3, 1, 1, 1, 3] num6_h = [3, 2, 1, 2, 2, 2, 2, 3] #num6_hb = [2, 2, 1, 3, 2, 2, 2, 3] num7_h = [4, 1, 1, 1, 1, 1, 1, 1] #num7_ha = [4, 1, 1, 0, 1, 1, 1, 1] num8_h = [2, 2, 2, 2, 4, 2, 2, 4] num9_h = [2, 2, 2, 3, 4, 1, 1, 3] #num9_ha = [2, 2, 2, 2, 4, 1, 1, 3]

  1. 识别函数
[code]def ocrsingle2(im,rec = []):
if rec == dot:
return '.'
if rec == num0 or rec == num0a or rec == num0b:
return '0'
if rec == num1 or rec == num1a:
return '1'
if rec == num2 or rec == num2a:
return '2'
if rec == num3 or rec == num3a:
return '3'
if rec == num4 or rec == num4a or rec == num4b:
return '4'
if rec == num5:
return '5'
if rec == num6 or rec == num6a or rec == num6b:
return '6'
if rec == num7 or rec == num7a or rec == num7b:
return '7'
#8和9的变形太多,纵向比较不好区分,通过扫描每一行的黑点特征比较
rech = []#用来记录数组的从上向下的断连情况
w, h = im.size
data = list(im.getdata())
for y in xrange(h):
s=0
for x in xrange(w):
if data[y*w +x] == 0:
s += 1
rech.append(s)
print rec
print rech
if rech[5] == 2 and rech[6] == 2:
return '8'
if rech[5] == 1 and rech[6] == 1:
return '9'
return '?'[/code]

经过试验,识别率应该在99%以上了,至少我下载的10涨图片,每张图片大平均应该有10组数字以上,都可以全部正确识别出来了。

最后引用总结一下图片识别的大致方法,以下文字来自:http://www.cnblogs.com/cntlis/archive/2009/01/14/1375694.htm l 1.图像二值化 二值化实现方法有 1.1图像灰度化-中值滤波等,同时可以实现背景的去除 1.2图像灰度化-根据灰度值 1.3根据图像色系范围进行二值化处理 2.去除噪点 去除噪点也可以分为如下: 2.1根据噪点周围的8个点的数目去除 2.2根据噪点周围的4个正向点去除 2.3根据有效链接点的数目去除 3.去除干扰线 一般干扰线都为1像素宽度,纵向或者横向的 4.图像修补,填充一些误删除的点,主要有以下几种方式: 4.1根据正向有效点的数目进行填充 4.2根据是否属于某直线的一部分进行填充 5.图像分割 查找连续的点,并组合数组,然后根据分割出来的长度,对字符进行组合或者分割 6.字符图像大小归一 将图像大小都设为一致 7.其他调整 抽骨、梯度等 8.查找特征点(譬如说图像的有效坐标等,根据具体情况具体分析),并确立图像对比方案,可以通过神经网络或者欧氏距离的方式 9.图片学习 做字库 10.图片识别!