输入图片,具有干扰线和噪点,且文字规则排布,例如

opencv 去掉验证码干扰_机器学习

,输出结果[1,0,9,2]

一:图片初步处理

利用阈值处理消掉干扰线,判断每个点周围的灰度值分布来消除噪点,获得比较干净的图片,处理结果

opencv 去掉验证码干扰_机器学习_02


阈值处理:设定一个阈值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)

二.切割原子级图片

我们需要将图片它分成四块减少训练量

opencv 去掉验证码干扰_Image_03


opencv 去掉验证码干扰_Image_04


opencv 去掉验证码干扰_opencv 去掉验证码干扰_05


opencv 去掉验证码干扰_opencv 去掉验证码干扰_06


切割原子图片的代码:

"""
    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的大小 ***

opencv 去掉验证码干扰_Image_07

opencv 去掉验证码干扰_python_08

四:训练并识别

#参考自
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

测试结果

opencv 去掉验证码干扰_python_09


opencv 去掉验证码干扰_图像识别_10