机器学习之初探验证码识别-Scikit learn

2017-4-9 小屿 Scikit-learn

最近尝试初探了一下验证码识别相关技术,发现这个也是蛮复杂的,涉及到图像处理,机器学习,卷积神经什么的,只探索了一点皮毛技术,后面会尝试尽可能的深入,不过英文数学水平是硬伤。

验证码识别常规思路是对图像进行处理,将彩色验证码二值化,去除噪点干扰,切割验证码,作为模型进行训练,然后进行测试

图像处理用到PIL库

def contrast(img):
    """ 增强图像的对比度 """
    # 增加对比度
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(5)
    # 锐化
    enhancer = ImageEnhance.Sharpness(img)
    img = enhancer.enhance(1)
    return img

灰度化并增强对比度后字符已经很明显了

def binaryzation(img):
    """ 图像二值化, 并返回黑点位置 """
    black_point = []
    for x in xrange(img.width):
        for y in xrange(img.height):
            if img.getpixel((x,y)) > 60:
                img.putpixel((x, y), 255)
            else:
                img.putpixel((x, y), 0)
                black_point.append((x,y))
    return black_point

二值化需要找到一个阙值,将偏向白的像素变白黑的变黑

def black_pixel_num(x, y, img):
    """ 爬行连续黑点数量 """
    check = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    for x_change,y_change in check:
        if (0 <= x+x_change < img.width) and (0 <= y+y_change < img.height): 
            if img.getpixel((x+x_change,y+y_change)) == 0: 
                black_is_checked.append((x+x_change,y+y_change)) 
                if (x+x_change,y+y_change) not in black_del: 
                    black_del.append((x+x_change,y+y_change)) 
def del_img_denoising(img):
    """ 去除噪点 """
    global black_is_checked
    black_is_checked = []
    for x,y in black_point:
        global black_del
        black_del = []
        # 减少检测次数,提升效率
        if (x,y) not in black_is_checked:
            black_is_checked.append((x,y))
            black_pixel_num(x,y,img)
            for x,y in black_del:
                black_pixel_num(x,y,img)
            if len(black_del) < 20: 
                img.putpixel((x, y), 255) 
                for x,y in black_del: 
                    img.putpixel((x, y), 255)

通过爬行黑像素面积判断噪点实现去


按照常规思路,接下来要做的就是切割字符,对于位置固定的可以进行固定切割,对于不固定的字符不相连的可以通过判断字符边缘来进行切割,还可以按颜切割色,以及滴水切割等等

通过判断字符边缘来进行切割:

def split_yzm_y(img):
    """ 沿y轴分割验证码 """
    black_pixel_get = []
    pixel_y = []
    for lenth in xrange(img.size[1]):
        pixel_y.append(0)
    for x in xrange(img.size[0]):
        for y in xrange(img.size[1]):
            if x in black_pixel_get:
                continue
            elif img.getpixel((x,y)) == 0:
                pixel_y[y] = 1
                black_pixel_get.append(y)
    split_y = []
    lenth = 0
    for i in xrange(len(pixel_y)):
        if pixel_y[i] == 1:
            split_y.append(i)
            break
    for i in xrange(len(pixel_y)):
        if pixel_y[i] == 1:
            lenth += 1
    split_y.append(lenth)
    return split_y

可见字符已经被切割为单独一个


机器学习用到sklearn库

将每个字符的图片用数组表示,字符用肉眼识别结果保存另一个结果,然后导入生成模型文件

model_file = 'model/SVC.pkl'
def train(data, target, model_save):
    classifier = svm.LinearSVC()
    classifier.fit(data, target)
    joblib.dump(classifier, model_save)
建立一个空数组长度为字符图片的个数,每个坑和图片高宽一致
np.empty((length, 19 * 28), dtype="float32")
然后读取每个字符图片数组表示导入
np.asarray(img, dtype="float32").flatten()
每个字符的结果也转入个数组然后用
train(data, target, model_save)
data为字符图片数组表示的数组集,target为数组的肉眼识别结果,model_save为保存路径
生成模型文件后导入模型文件就可以识别了
clf = joblib.load('model/SVC.pkl')
result = clf.predict(yzm)
result_yzm = ''
for char in result:
    result_yzm += chr(int(char))
print result_yzm

用园长表哥公司验证码试了下,训练了100张验证码,400个字符,就达到了大约%90正确率。后续会继续学习,尝试挑战BAT验证码。 

标签: 机器学习 Scikit-learn

评论:

Lottie
2017-06-10 08:04
That's a smart answer to a diffciult question.

发表评论:

Powered by xia0yu