12.1 更新

来自我的博客: PIL 识别简单验证码

已经有完整的代码了

=======================================

新手, 多多指教

大概思路: 1. 转换图片为黑白, 2. 去除干扰, 3. 切割, 4. 识别

<1>

采集足够的验证码图片

要识别的验证码都是简单的, 字体一致, 无变形, 干扰少,位置固定(适合新手)

采集代码(隐去网址)

for i in range(500): url = rhttp://xxxx/default3.html urllib.urlretrieve(url, str(i) + .gif)

<2>

切割转换图片, 返回为图片块

rct 为五个数字的四条边的位置, 由于位置固定所以通过手动微调得到大概值

import osfrom PIL import Imagedef get_cut(file_name): img = Image.open(file_name) cut_img = [] # 每个数字的范围 rct = ( (5, 5, 15, 19), # 左边距 上边距 右边距 下边距 (14, 5, 24, 19), (23, 5, 33, 19), (32, 5, 42, 19), (41, 5, 51, 19) ) # 转换图片 bin_img = get_bin(img) # 将图片分割为五部分 for part in range(5): cut_img.append(bin_img.crop(rct[part])) return cut_img

切割后的图片大概如下:

保存切割的图片代码如下, 测试的时候用:

for i in range(20): img = get_cut(img\ + str(i) + .gif) d = 0 for im in img: d += 1 im.save(cut\ + str(i) + str(d) + .gif)

<3>

把图片转换为灰度图 , 去除噪音部分, 转换为黑白

由图可看出, 数字部分颜色比较暗, 背景部分偏亮, 转换为灰度图, 将亮的部分去除得到的就是有效的数字部分像素, 阈值可用ps, 或者用代码计算出亮度信息集中部分, 将高于阈值的部分去除

# 去除图片噪点并转为黑白def get_bin(img): bin_img = Image.new(L, img.size, 255) # 新图片 模式 L灰度 大小 色彩深度 cvt_img = img.convert("L") # 转换模式为灰度图 for x in range(img.size[1]): for y in range(img.size[0]): pix = cvt_img.getpixel((y, x)) if pix < 110: # 去噪阈值过滤灰度大于 110 的像素点 bin_img.putpixel((y, x), 0) # 填充新图片 else: bin_img.putpixel((y, x), 255) return bin_img

<4>

将图片每个像素点转换为 0, 1 值对应的字典,1代表有, 0 代表无

# 转换为矢量def buildvector(img): d1 = {} count = 0 for i in img.getdata(): d1[count] = 0 if i ==255: d1[count] = 1 count += 1 return d1

<5>

识别图片块数字, 将要识别的图片转换为二值对应的字典, 读取已知的图片并与要识别的图片比较, 比较的方法是对比x每一行, y每一列, 将一样的值计数统计除以总像素计算出相似度, 并返回相似度最高的图片的值

# 识别每个图片块的内容def get_result(src_img): guess = -1 # 将图片转换为二值列表 srcimgbin = buildvector(src_img) # 用于储存每个对比数字的相似率 simalist = [] for i in range(10): simalist.append(0) # 与每个数字对比 for cp_numb in range(10): cp_count = len(os.listdir(convert_Img\%s % cp_numb)) # 遍历比较已知数字图片块集合目录 for comp in os.listdir(convert_Img\%s % cp_numb): cpimgpath = convert_Img\ + str(cp_numb) + \ + comp # 将已知块转换 cp_bin =buildvector(get_bin(Image.open(cpimgpath))) xy = 0 yx = 0 # 纵向扫描对比 并统计相同 for x in range(10): for y in range(14): if cp_bin[x * y + y] == srcimgbin[x * y + y] == 1: xy += 1 # 横向扫描对比 for y in range(14): for x in range(10): if cp_bin[y * x + x] == srcimgbin[y * x + x] == 1: yx += 1 # 得出单张图片相似率 sima = (xy + yx) / 280 # 统计该数相似率 simalist[cp_numb] += sima # 求于个数平均值 simalist[cp_numb] /= cp_count # 得到相似度最高的数字 guess = getmax(simalist) return guess# 获取列表最大数def getmax(list): li = list max = 0 index = 0 for i in range(len(li)): if max < li[i]: max = li[i] index = i return index

<6>

主函数循环识别一百张张图片验证码内容,将识别结果命名为图片名

if __name__ == __main__: for i in range(100): # 得到只有黑白值的图片分割块 cut_img = get_cut(img\ + str(i) + .gif) result = # 识别每个图片块的内容 for im in cut_img: # 将识别的结果连接 result = result + str(get_result(im)) print result # 重命名文件名为识别结果 os.rename(img\ + str(i) + .gif,img\ + result + .gif)

识别结果

待解决问题, 将已标记的图片先转换为二值标记文件, 8 会识别为 3 ,原因是还有干扰的点

待更新 . . .


推荐阅读:
相关文章