一种识别简单验证码的方法

  • Post author:
  • Post category:其他


本文主要讲述了一种识别简单验证码的方法,本文重点不是识别这些简单的数字,而是通过识别数字这个过程理解到图片的数字构造。任何一张图片都是由三个图层构成的,每个图层是一张二维矩阵表,三张表上位置相同的三个数值组成一个像素点,数值范围是0到255,黑白图片三张表是相同的,所以是256种颜色,彩色图片三张表的数值不一样,所以液晶电视打广告的真彩色有256

256

256=16777216种颜色。

识别步骤主要分为3步:

1、对验证码图片打标签并创建文字和图片一一对应的识别模板集,以供后续比对使用;

2、提取待识别验证码图片并按照模板创建的规则创建图片集;

3、把待识别的图片集和模板集进行比对,以判断待识别的图片是什么文字。

本文用的匹配方法是位置匹配,是将像素点在图片中的位置转换为二维坐标值,左下角为原点(0,0)。匹配的时候是将两张图片的坐标进行比对,待识别图片坐标值在与之匹配的图片中有相同坐标值的,正确数+1,反之错误数+1,公式如下:

匹配率 = (正确数 – 错误数)/ 待识别图片坐标总数 * 100%

文件构成:

在这里插入图片描述

待识别图片:

待识别图片

图片特征库:

图片特征库

提取图片像素后坐标化:

提取图片像素后坐标化

提取图片中的一个数字:

提取图片中的一个数字

运行结果:

运行结果

图片识别部分:

import numpy as np
import random
from PIL import Image
import matplotlib.pyplot as plt
import os
import operator
import k_means1
import time

def Mapping1(mpp): #绘图
    if mpp!=[]:
        colors=['b','g','r','c','m','y','k']
        s=0
        for j in mpp:
            plt.plot(j[0], j[1], color=colors[s%len(colors)], marker='.')
        plt.ion()
        plt.show()
        plt.pause(3)
        plt.close()

def Mapping2(mpp): #绘图
    if mpp!=[]:
        colors = ['b','g','r','c','m','y','k']
        s=0
        for j in mpp:
            for i in j:
                plt.plot(i[0], i[1], color=colors[s%len(colors)], marker='.')
            s = s+1
        #plt.ion()
        plt.show()
        #plt.pause(3)
        #plt.close()

#提取图片中的字符(通用函数)
def Picture_processing(image,characters): #输入一张图片,返回4个列表
    #print(image.format, image.size, image.mode)
    #image_array = image.load(); #获取像素点
    #image.show()
    gray = image.convert("L"); #转换灰度
    gray_array = gray.load(); #获取像素点

    #2分类去除淡色部分
    data = []
    for j in range(0,image.size[0]):
        for i in range(0,image.size[1]):
            #print(gray_array[j,i])
            data.append(gray_array[j,i])
    data_list = k_means1.k_means(data,2); #k个均值分k份

    #提取黑色部分坐标
    mpp = []
    for j in range(0,image.size[0]):
        for i in range(0,image.size[1]):
            if gray_array[j,i]<data_list[1][0]:
                gray_array[j,i] = 0
                mpp.append([j,image.size[1]-i])
            else:
                gray_array[j,i] = 255
    #Mapping1(mpp); #绘图

    #按照图片字符分4组
    mpp2 = []
    for j in range(0,len(characters)):
        mpp2.append([])
    for j in mpp:
        if j[0]<=17:
            mpp2[0].append(j)
        if 17<j[0]<=30:
            mpp2[1].append(j)
        if 30<j[0]<=43:
            mpp2[2].append(j)
        if 43<j[0]:
            mpp2[3].append(j)
    #Mapping2(mpp2); #绘图

    #x轴向0点移动
    for j in range(0,len(mpp2)):
        mpp2[j].sort(reverse=False,key=operator.itemgetter(0))  #正序
        min0 = mpp2[j][0][0]
        for i in range(0,len(mpp2[j])):
            mpp2[j][i][0] = mpp2[j][i][0]-min0
    #y轴向0点移动
    for j in range(0,len(mpp2)):
        mpp2[j].sort(reverse=False,key=operator.itemgetter(1))  #正序
        min0 = mpp2[j][0][1]
        for i in range(0,len(mpp2[j])):
            mpp2[j][i][1] = mpp2[j][i][1]-min0
    #for j in mpp2:
    #    Mapping2([j]); #绘图
        
    mpp3 = mpp2[0:4]; #返回4个字符图案
    
    for j in range(0,len(mpp3)):
        for i in range(0,len(mpp3[j])):
            mpp3[j][i] = (str(mpp3[j][i][0])+','+str(mpp3[j][i][1]))
    mpp4 = []
    for j in range(0,len(mpp3)):
        mpp4.append([mpp3[j],characters[j],len(mpp3[j]),(str(characters[j])+','+str(len(mpp3[j])))]); #像素点数特征,字符,像素点数量
    return mpp3,mpp4

#提取图片
def get_picture_library():
    images = []
    photos = os.listdir(os.getcwd()+'\\3 验证码特征库')
    for j in photos:
        images.append(Image.open(os.getcwd()+"\\3 验证码特征库\\"+j))
    return images,photos

#构建图库特征
def get_feature_library(): #返回图库特征
    
    images,photos = get_picture_library() #提取图片
    wb1 = []
    for j in photos:
        wb1.append([j[0],j[1],j[2],j[3]]); #提取文件名前4个字符
        
    mpp5 = []
    for image,j in zip(images,wb1):
        mpp3,mpp4 = Picture_processing(image,j); #输入一张图片,返回3个列表(3个字符)
        mpp5.extend(mpp4)
        
    Unique_set = set()
    for j in mpp5:
        Unique_set.add(j[3])
    mpp6 = []
    for j in Unique_set:
        for i in mpp5:
            if j==i[3]:
                mpp6.append(i)
                break
            
    mpp6.sort(reverse=False,key=operator.itemgetter(1))  #正序
    mpp6.sort(reverse=False,key=operator.itemgetter(2))  #正序
    #for j in mpp6:
    #    print(j[1],j[2],j[3]) #0是坐标特征(坐标值)列表,1是表征字符,2是坐标点数,3是1和2的字符结合
    return mpp6

#提取图片
def get_sample_picture():
    images = []
    photos = os.listdir(os.getcwd()+'\\1 验证码')
    for j in photos:
        images.append(Image.open(os.getcwd()+"\\1 验证码\\"+j))
    return images,photos

#单张图片识别
def image_recognition(mpp6): #图片识别

    images,photos = get_sample_picture() #提取图片
    wb1 = []
    for j in photos:
        wb1.append(['a','b','c','d'])
    
    mpp5 = []
    for image,j in zip(images,wb1):
        mpp3,mpp4 = Picture_processing(image,j); #输入一张图片,返回4个列表(4个字符)
        mpp5.extend(mpp4)

    wb2 = []
    for j in mpp5: #样本
        temporary_list = []
        for i in mpp6: #图库
            yes = 0
            no = 0
            for m in j[0]: #样本坐标特征列表
                if m in i[0]:
                    yes = yes+1
                else:
                    no = no+1
            temporary_list.append([i[1],yes,no,int((yes-no)/j[2]*10000)/100]); #字符,正确数,错误数,匹配率
            #j[2]是样本中图片的坐标点数,因为前面是按照样本的坐标点数来计数正确和错误数的,又因为全部图片不是一样大小的,
            #所以只有用计数的坐标总点数,如能完全匹配,匹配率才能刚好100%
        temporary_list.sort(reverse=False,key=operator.itemgetter(2)); #错误数升
        temporary_list.sort(reverse=True,key=operator.itemgetter(1));  #准确数降序
        temporary_list.sort(reverse=True,key=operator.itemgetter(3));  #匹配率降序
        wb2.append(temporary_list[0]) #提取匹配率最高的数字
    return wb2

def main():
    #构建图库特征
    mpp6 = get_feature_library()

    #单张图片识别
    data = image_recognition(mpp6)

    print("数字,正确数,错误数,匹配率")
    rec = ''
    for j in data:
        print(j)
        rec = rec + j[0]
    print()
    print("识别结果:",rec)
    return rec

if __name__=='__main__':

    main()

    time.sleep(60)

k-means函数:

import numpy as np
import random

def func00():    #生成随机数列表

    #random.seed(1)
    kjz1=[random.randint(1,50) for j in range(0,7000)]
    kjz1.extend([random.randint(80,150) for j in range(0,8000)])
    kjz1.extend([random.randint(200,300) for j in range(0,5000)])
    kjz1.extend([random.randint(400,500) for j in range(0,8000)])
    return kjz1

def func01(kjz1):    #2分类

    bj=1;kjz1=np.sort(kjz1)
    while(True):
        if bj==1:
            kj=np.mean([kjz1[0],kjz1[len(kjz1)-1]]) #初始分组均值使用最小值和最大值的平均值
        else:
            k1=s1;k2=s2;
            kj=np.mean([k1,k2]);
        kjz2=[[],[]];
        for j in kjz1:
            if j<=kj:
                kjz2[0].append(j)
            else:
                kjz2[1].append(j)
        s1=np.mean(kjz2[0]);
        s2=np.mean(kjz2[1]);
        if bj==2:
            if s1==k1 and s2==k2:
                break
        bj=2;
    return kjz2

def func02(kjz1,k):    #k个均值分k份

    kjz1=np.sort(kjz1);#正序
    wb2=kjz1.copy();
    #初始均匀分组wb1
    xlb=[];a=round(len(wb2)/(k));b=len(wb2)%(k);
    for j in range(1,k+1):
        xlb.append(j*a)
        if j==k:
            xlb[j-1]=xlb[j-1]+b;
    j=0;wb1=[];
    for j in range(0,k):
        wb1.append([])
    i=0;j=0;
    while(i<=len(wb2)-1):
        wb1[j].append(wb2[i]);
        if i>=xlb[j]-1:
            j=j+1;
        i=i+1;
    kj1=means(wb1);#初始分组均值

    bj=1;
    while(True):
        wb2=kjz1.copy().tolist();
        if bj!=1:
            kj1=kj2.copy();

        wb3=[];
        for j in range(0,k-1):
            wb3.append([])
        for j in range(0,k-1):
            i=-1;
            while(True):
                if wb2[i]<=kj1[j]:
                    wb3[j].append(wb2.pop(i));
                else:
                    i=i+1;
                if i>=len(wb2):
                    break
        wb3.append(wb2)

        kj2=means(wb3);#过程均值
        if bj==2:
            if kj1==kj2:
                break
        bj=2;
    return wb3

def means(lb1):    #计算均值

    mean1=[];mean2=[];std1=[];
    for j in lb1:
        mean1.append(np.mean(j).tolist())
    for j in range(1,len(mean1)):
        mean2.append(np.mean([mean1[j-1],mean1[j]])) #分组均值使用各组的均值
    return mean2

def k_means(data,k):

    #data=func00()    #生成随机数列表
    
    #kjz2=func01(data)    #2分类
    kjz3=func02(data,k)    #k个均值分k份
    return kjz3



版权声明:本文为qq_24311495原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。