简单验证码识别项目
基于逻辑回归和图像处理的项目
输入:一个验证码图像
输出:这个验证码图像中的数字(字母)
我们的需求是需要将一张彩色,由四个数字且有噪点所构成的提交给计算机,让计算机对该图片进行识别。从上述条件分析可知,我们需要以下步骤:
- 首先对图像进行处理,分为以下三小步:
(1)二值化:首先把图像从RGB3通道转化成Gray1通道,然后把灰度图(0~255)转化成二值图(0,1),简单来说就是将彩色的图片转为黑白的,只有两个颜色时,黑和白两个颜色就可以通过1,0两个数字进行表示。
(2)降噪:通过处理孤立点,对二值化的图进行降噪,由于图片都是由一个个小的像素点合成的,所以当一个像素点周围空白点大于四个,咱们就认为他是一个孤立点。
(3)图片切割:根据像素格,把图片中的所有(4个)数字,分别保存到对应的0~9文件夹下,供机器进行识别。
至此:数据处理就完成了,我们来看看上述部分的代码:
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import random
import numpy as np
import matplotlib.pyplot as plt
import os
def getRandomStr():
random_num = str(random.randint(0, 9))
return random_num
def getRandonColor():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
if c1 == 255:
c1 = 0
if c2 == 255:
c2 = 0
if c3 == 255:
c3 = 0
return c1, c2, c3
def generate_captcha():
image = Image.new('RGB', (150, 50), (255, 255, 255))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype('LiberationSans-Bold.ttf', size=32)
label = ''
for i in range(5):
random_char = getRandomStr()
label += random_char
draw.text((10 + i * 30, 0), random_char, getRandonColor(), font=font)
width = 150
height = 30
for i in range(3):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=(0, 0, 0))
for i in range(5):
draw.point([random.randint(0, width), random.randint(0, height)], fill=getRandonColor())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=(0, 0, 0))
image.save(open(''.join(['captcha_new/', label, '.png']), 'wb'), 'png')
def binarization(path):
img = Image.open(path)
img_gray = img.convert("L")
img_gray = np.array(img_gray)
print(img_gray)
w, h = img_gray.shape
for x in range(w):
for y in range(h):
gray = img_gray[x, y]
if gray <= 220:
img_gray[x, y] = 0
else:
img_gray[x, y] = 1
plt.figure('')
plt.imshow(img_gray, cmap='gray')
plt.axis('off')
# plt.show()
return img_gray
def nosieReduction(img_gray, label):
height, width = img_gray.shape
for x in range(height):
for y in range(width):
cnt = 0
if img_gray[x, y] == 1:
continue
else:
try:
if img_gray[x - 1, y - 1] == 0:
cnt += 1
except:
pass
try:
if img_gray[x - 1, y] == 0:
cnt += 1
except:
pass
try:
if img_gray[x, y - 1] == 0:
cnt += 1
except:
pass
try:
if img_gray[x + 1, y] == 0:
cnt += 1
except:
pass
try:
if img_gray[x, y + 1] == 0:
cnt += 1
except:
pass
try:
if img_gray[x + 1, y + 1] == 0:
cnt += 1
except:
pass
try:
if img_gray[x - 1, y + 1] == 0:
cnt += 1
except:
pass
try:
if img_gray[x + 1, y - 1] == 0:
cnt += 1
except:
pass
if cnt < 4:
img_gray[x, y] = 1
plt.figure('')
plt.imshow(img_gray, cmap='gray')
plt.axis('off')
# plt.show()
plt.savefig(''.join(['CLEAN_captcha_img/',label,'.png']))
def img_2_clean():
captchas = os.listdir(''.join(['captcha_images/']))
for captcha in captchas:
print(captcha)
label = captcha.split('.')[0]
img_path = ''.join(['captcha_images/', captcha])
im = binarization(img_path)
nosieReduction(im, label)
def cutImg(label):
labels = list(label)
img = Image.open(''.join(['CLEAN_captcha_img/', label, '.png']))
for i in range(5):
pic = img.crop((100 * (1 + i), 170, 100 * (1 + i) + 100, 280))
plt.imshow(pic)
seq = get_save_seq(label[i])
pic.save(''.join(['cut_number/', str(label[i]), '/', str(seq), '.png']))
def get_save_seq(num):
numlist = os.listdir(''.join(['cut_number/', num, '/']))
if len(numlist) == 0 or numlist is None:
return 0
else:
max_file = 0
for file in numlist:
if int(file.split('.')[0]) > max_file:
max_file = int(file.split('.')[0])
return int(max_file)+1
def create_dir():
for i in range(10):
os.mkdir(''.join(['cut_number/', str(i)]))
def clean_to_cut():
captchas = os.listdir(''.join(['CLEAN_captcha_img/']))
for captcha in captchas:
label = captcha.split('.')[0]
cutImg(label)
if __name__ == '__main__':
for i in range(1):
generate_captcha()
# img_2_clean()
# create_dir()
# clean_to_cut()
# path = 'captcha_images/'
# binarization()
以上还有生成的验证码的代码,生成结果为:
至此:数据处理就完成了接下来需要:
2. 把数据带入逻辑回归进行建模
(1)把切割好的数据,按照X(二位数组),Y(一维数组)的方式传入logisticRegression.fit()函数进行拟合
我们可以通过网格搜索(GridSearch)来进行调参
(2)通过joblib包,把模型保存到本地
我们需要对得出的数据进行逻辑回归:
import os
from PIL import Image
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.externals import joblib
from check_code import *
def load_data():
X, Y = [], []
cut_list = os.listdir('cut_number')
for numC in cut_list:
num_list_dir = ''.join(['cut_number/', str(numC), '/'])
nums_dir = os.listdir(num_list_dir)
for num_file in nums_dir:
img = Image.open(''.join(['cut_number/', str(numC), '/', num_file]))
img_gray = img.convert('L')
img_array = np.array(img_gray)
w, h = img_array.shape
for x in range(w):
for y in range(h):
gray = img_array[x, y]
if gray <= 240:
img_array[x, y] = 0
else:
img_array[x, y] = 1
img_re = img_array.reshape(1, -1)
X.append(img_re[0])
Y.append(int(numC))
return np.array(X), np.array(Y)
def generate_model(X, Y):
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3)
log_cif = LogisticRegression(multi_class='ovr', solver='sag', max_iter=10000)
log_cif.fit(X_train, Y_train)
joblib.dump(log_cif, 'captcha_model/captcha_model.model')
def get_model():
model = joblib.load('captcha_model/captcha_model.model')
return model
def captcha_predict():
path = 'captcha_new/unkonwn.png'
pre_img_gray = binarization(path)
nosieReduction(pre_img_gray, 'unknown')
labels = ['0', '1', '2', '3', '4']
img = Image.open(''.join(['CLEAN_captcha_img/unknown.png']))
for i in range(5):
pic = img.crop((100 * (i + 1), 170, 100 * (1 + i) + 100, 280))
plt.imshow(pic)
pic.save(''.join(['captcha_new/', labels[i], '.png']))
result = ''
model = get_model()
for i in range(5):
path = ''.join(['captcha_new/', labels[i], '.png'])
img = Image.open(path)
img_gray = img.convert('L')
img_array = np.array(img_gray)
w, h = img_array.shape
for x in range(w):
for y in range(h):
gray = img_array[x, y]
if gray <= 220:
img_array[x, y] = 0
else:
img_array[x, y] = 1
img_re = img_array.reshape(1, -1)
X = img_re[0]
y_pre = model.predict([X])
result = ''.join([result, str(y_pre[0])])
return result
if __name__ == '__main__':
X,Y =load_data()
generate_model(X,Y)
当模型生成好了之后就可以对给入的数据进行对比了:
调用此函数:
if __name__ == '__main__':
result = captcha_predict()
print(result)
结果如下: