输入图片,具有干扰线和噪点,且文字规则排布,例如
,输出结果[1,0,9,2]
一:图片初步处理
利用阈值处理消掉干扰线,判断每个点周围的灰度值分布来消除噪点,获得比较干净的图片,处理结果
阈值处理:设定一个阈值G,当图片转为灰度图后,如果该点的灰度值小于阈值则为白色,大于阈值则为黑色
降噪处理:比较该点与周围八个点灰度值,如果相等数量若低于设定数量N,则判定该点为噪点
"""
验证码二值化和降噪
参考自
"""
import sys, os
from PIL import Image, ImageDraw
# 二值数组
t2val = {}
def twoValue(image, G):
"""
原理设定一个阈值G,当图片转为灰度图后,如果该点的灰度值小于阈值则为白色,大于阈值则为黑色
"""
for y in range(0, image.size[1]):
for x in range(0, image.size[0]):
g = image.getpixel((x, y))
if g > G:
t2val[(x, y)] = 1
else:
t2val[(x, y)] = 0
def clearNoise(image, N, Z):
"""
降噪原理:比较该点与周围八个点灰度值,如果相等数量若低于设定数量N,则判定该点为噪点
"""
for i in range(0, Z):
t2val[(0, 0)] = 1
t2val[(image.size[0] - 1, image.size[1] - 1)] = 1
for x in range(1, image.size[0] - 1):
for y in range(1, image.size[1] - 1):
nearDots = 0
L = t2val[(x, y)]
if L == t2val[(x - 1, y - 1)]:
nearDots += 1
if L == t2val[(x - 1, y)]:
nearDots += 1
if L == t2val[(x - 1, y + 1)]:
nearDots += 1
if L == t2val[(x, y - 1)]:
nearDots += 1
if L == t2val[(x, y + 1)]:
nearDots += 1
if L == t2val[(x + 1, y - 1)]:
nearDots += 1
if L == t2val[(x + 1, y)]:
nearDots += 1
if L == t2val[(x + 1, y + 1)]:
nearDots += 1
if nearDots < N:
t2val[(x, y)] = 1
def crop_image(img, box, dirs):
img.crop(box).save(dirs + str(i) + ".png")
def saveImage(filename, size):
image = Image.new("1", size)
draw = ImageDraw.Draw(image)
for x in range(0, size[0]):
for y in range(0, size[1]):
draw.point((x, y), t2val[(x, y)])
image.save(filename)
if __name__ == '__main__':
for i in range(1, 101):
path = "striped_imgs/" + str(i) + ".png"
image = Image.open(path)
image = image.convert('L')
twoValue(image, 125)
clearNoise(image, 3, 1)
path1 = "striped_imgs" + str(i) + ".jpg"
saveImage('2value/' + path1, image.size)
二.切割原子级图片
我们需要将图片它分成四块减少训练量
切割原子图片的代码:
"""
1.裁剪图片
2.切割原子级图片
参考自
"""
from PIL import Image
def smartSliceImg(img, outDir, ii, count=4, p_w=3):
'''
:param count: 图片中有多少个图片
:param p_w: 对切割地方多少像素内进行判断
:return:
'''
w, h = img.size
pixdata = img.load()
eachWidth = int(w / count)
beforeX = 0
for i in range(count):
allBCount = []
nextXOri = (i + 1) * eachWidth
for x in range(nextXOri - p_w, nextXOri + p_w):
if x >= w:
x = w - 1
if x < 0:
x = 0
b_count = 0
for y in range(h):
if pixdata[x, y] == 0:
b_count += 1
allBCount.append({'x_pos': x, 'count': b_count})
sort = sorted(allBCount, key=lambda e: e.get('count'))
nextX = sort[0]['x_pos']
box = (beforeX, 0, nextX, h)
img.crop(box).save(outDir + str(ii) + "_" + str(i) + ".png")
beforeX = nextX
def crop_img():
for i in range(1, 101):
path = "2value/striped_imgs" + str(i) + ".jpg"
img = Image.open(path)
w, h = img.size
outDir = '2value/strip/'
box = (7, 0, w - 15, h)
img.crop(box).save(outDir + str(i) + ".png")
for i in range(1, 101):
path = "2value/strip/" + str(i) + ".png"
img = Image.open(path)
outDir = '3qiege/'
smartSliceImg(img, outDir, i, count=4, p_w=2)
#crop_img()
三:分类
我们需要告诉机器,哪张图片是0,哪张图片是9,当模型积累到一定程度后,就可以让机器自己去识别了.
将我们切割的原子图片手动分为10个文件夹,每个文件夹放30-40个图片
***注意:每张图片的大小应相等,刚开始我没注意,后来才将所有图片重新设定成15X30的大小 ***
四:训练并识别
#参考自
import joblib
import numpy as np
import os
from PIL import Image
from sklearn.neighbors import KNeighborsClassifier
def load_dataset():
X = []
y = []
for i in "0123456789":
target_path = "fenlei/resize/new/" + i
if not os.path.exists(target_path):
os.makedirs(target_path)
for title in os.listdir(target_path):
pix = np.asarray(Image.open(os.path.join(target_path, title)).convert('L'))
X.append(pix.reshape(15 * 30)) # 二维降为一维
y.append(target_path.split('/')[-1])
X = np.asarray(X)
y = np.asarray(y)
return X, y
def check_everyone(model, part_path):
pre_list = []
y_list = []
if not os.path.exists(part_path):
os.makedirs(part_path)
for title in sorted(os.listdir(part_path)):
pix = np.asarray(Image.open(os.path.join(part_path, title)).convert('L').resize((15, 30)))
pix = pix.reshape(15 * 30)
pre_list.append(pix)
y_list.append(part_path.split('/')[-1])
pre_list = np.asarray(pre_list)
y_list = np.asarray(y_list)
result_list = model.predict(pre_list)
acc = 0
for i in result_list == y_list:
if i == np.bool(True):
acc += 1
print(result_list)
return result_list
X, y = load_dataset()
knn = KNeighborsClassifier()
knn.fit(X, y)
joblib.dump(knn, 'cnki.model')
if __name__ == '__main__':
for i in "0123456789":
try:
check_everyone(knn, part_path="part/" + i + '/')
except:
pass
测试结果