不久前趁着项目需求空档时间,捡起很久没有看的Python,翻了几天的Python视觉计算。对sklearn这个基础数学库有些兴趣,就略微看了看。正好联想到之前的验证码,就索性用C#生成了一些简单的标准数字图片,做一些实验。
-
1.图片准备
-
2.简单图片切割
-
3.简单的图片处理
-
4.连续处理
-
5.简单识别
-
6.分类图片
-
7.人工分类
-
8.二值化
-
9.使用sklearn进行预测
-
10.思考
-
11.参考资料
1.图片准备
首先我们引入一下基本的图片操作,和文件操作的python库,有点像C#的using命名空间
import requests
import time
from PIL import Image, ImageFilter, ImageEnhance # 操作图像
import os
import fnmatch
import sys
使用ASP.NET写了一个简单的页面,生成了一些数字图片,每张图片4个均匀分散的数字。
注:生成的数字宋体,不发散,不倾斜,无连体…
下载一下生成的图片保存到本地,
def down_pic(picName):
url = "http://localhost:8891/code.aspx"
res = requests.get(url, stream=True)
with open('./pic/%s.jpg' % (picName), 'wb') as f:
for chunk in res.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
f.flush()
f.close()
做一个简单的循环以保证保存到足够多的图片:
# for i in range(300):
# picName = int(time.time()*100000)
# down_pic(picName)
2.简单图片切割
验证码识别中比较重要的是分割图片,在这里就暂时不再赘述了,这一点会在后面的博文中做重点讲述。
从一个路径读取图片:
def readPic(picUrl):
return Image.open(picUrl)
这里的图片比较简单,我们切分一下:
def cutPic(img):
# 72*30
x = 6 # 10
y = 5 # 7
w = 8 # 9
h = 12 # 17
interval = 1 # 2
newImgs = []
for i in range(5):
print(i)
newImg = img.crop(
(x+w*i+interval*i, y, x+w*(i+1)+interval*i, y+h)) #左上右下
newImgs.append(newImg)
# newImg.convert('RGB').save('10.jpg', 'JPEG')
# print(newImg)
return newImgs
3.简单的图片处理
增强图片对比度,转为灰度图
def transfer(img):
img.filter(ImageFilter.MedianFilter()) # 滤波器
enhancer = ImageEnhance.Contrast(img)
img = enhancer.enhance(1) # 对比度 增强
return img.convert('L') # 灰度
4.连续处理
那么,我们将上面的方法综合起来:
读取一批图片=>分割图片成单个数字图片=>存储到新的文件夹中
def beginRead(filename):
img = readPic(filename).convert('RGB')
newImg = transfer(img)
pics = cutPic(newImg)
for pic in pics:
pic.save('./pics/%s.jpg' %
(int(time.time()*1000000)), 'jpeg')
5.简单识别
使用pytesseract对图片进行简单的识别,注意要安装一下openvc。
可以使用下面的方式。
# ocr
# 必须要安装这里的 https://github.com/UB-Mannheim/tesseract/wiki
# for windows https://github.com/tesseract-ocr/tesseract/wiki/4.0-with-LSTM#400-alpha-for-windows
# x from tesseract import image_to_string
import pytesseract
ocr图片:
def ocrImage(fileUrl):
# print(fileUrl)
img = readPic(fileUrl)
# print('1')
# content = pytesseract.image_to_string(img,lang='chi_sim')
# content = pytesseract.image_to_string(img, lang='eng', boxes=False,
# config='--psm 10 --oem 3 -c tessedit_char_whitelist=0123456789')
# content = pytesseract.image_to_string(
# img, config="--psm 10 -c tessedit_char_whitelist=0123456789")
try:
# content = pytesseract.image_to_string(img, config="-psm 7")
content = pytesseract.image_to_string(
img, config="--psm 10 -c tessedit_char_whitelist=0123456789")
# print(content)
# if content == 0 | content == 1 | content == 2 | content == 3 | content == 4 | content == 5 | content == 6 | content == 7 | content == 8 | content == 9:
# return content
# else:
# return "none"
pattern = re.compile(r'([0-9]+)', re.I)
m = pattern.match(content)
if m.groups() == 0:
print('None')
return 'none'
else:
print(content)
return content
except:
print('Err')
return 'none'
# print(content)
return content
6.分类图片
将识别的图片copy到新的文件夹进行分类:
def copyToCat(originfile, dir, filename):
# print(originfile, dir, filename)
if not os.path.exists(dir):
os.makedirs(dir)
shutil.copyfile(originfile, dir+'/'+filename)
我们将上述两个方法连续起来:
读取处理后的文件夹中图片列表=>对图片进行ocr识别=>将识别出来的图片归类=>未识别出来的同意放到none文件夹
def location(dir):
for filename in os.listdir('./'+dir+'/'):
if fnmatch.fnmatch(filename.lower(), '*.jpg'):
fileUrl = './'+dir+'/'+filename
if dir == 'pic':
begin(fileUrl)
else:
result = ocrImage(fileUrl)
copyToCat(fileUrl, './cat/%s' % result, filename)
7.人工分类
对已经分类的图片人工检查一下,错误的手动分类一下,对未识别出来的再手动进行一下分类。
可以保留一些未分类的图片以供后面作为测试集使用。
已经自动分类的和部分人工分类的作为训练集使用。
8.二值化
将一张图片二值化:
def imgTo01(img):
pixdata = img.load()
w, h = img.size
str = ''
for x in range(w):
for y in range(h):
if pixdata[x, y] < 127:
str += '0'
else:
str += '1'
return str
调用上面的方法对所有图片二值化,并将上一步中得到的训练集和测试进行二值化,并保存为csv文档。
这时候,需要引入pandas进行csv的读写操作。
import shutil
import re # 正则
import pandas as pd
批量处理
def saveTocsv():
columns_train = []
columns_test = []
for i in range(10):
for filename in os.listdir('./cat/%s' % i):
print(filename)
# 灰度 二值化
img = readPic('./cat/%s' %
i+'/'+filename).convert('L').convert('1')
str = imgTo01(img)
columns_train.append({
'raw': str,
'num': i
})
df_train = pd.DataFrame(columns_train, columns=['raw', 'num'])
df_train.to_csv('train.csv')
for filename in os.listdir('./cat/none'):
print(filename)
# 灰度 二值化
img = readPic('./cat/none/'+filename).convert('L').convert('1')
str_test = imgTo01(img)
columns_test.append({
'raw': str_test,
'num': 'none',
'filename': filename
})
df_test = pd.DataFrame(columns_test, columns=['raw', 'num'])
df_test.to_csv('test.csv')
9.使用sklearn进行预测
这里就不再简述为什么要使用K近邻邻算法了,你可以自行Google文档查询想要的答案。
def skl():
data = pd.read_csv('./train.csv') # 读取训练集
x_train = data.drop(['num'], axis=1) # 特征值 raw二值化数据
y_train = data['num'] # 目标值 number值
# x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
# print(x_train.shape)
# print(y_train.shape)
data_test = pd.read_csv('./test.csv') #读取测试集
x_test = data_test.drop(['num'], axis=1) #测试集 raw二值化数据
knn = KNeighborsClassifier(n_neighbors=5) #K近邻算法
knn.fit(x_train, y_train)
# sgd = SGDRegressor()
y_predict = knn.predict(x_test)
# 重命名
# img = readPic('./cat/none/'+filename).convert('L').convert('1')
for index in range(len(y_predict)):
filename = data_test[index]['filename']
y_predict[index]
print(x_test['raw'])
# print(y_predict)
# print('%:', knn.score(x_test, y_test))
我们可以看到,当k值越小,得到的预测值正确率越高。
上一张图看一下识别效果:
当然这里的数字很简单。
10.思考
上的二值化的结果比较小,如果我们遇到二值化的数据量比较大,甚至单个数据都比较大的情况呢?怎么预测?
标准化?当你使用标准化都爆出溢出呢,又该怎么办。
后面,我们将使用 sklearn 和 tensflow 对简单的手写字体进行预测,那里将会面临这个问题,敬请期待。