基于决策树的简单验证码识别

原理

核心思想:相似的输入必会产生相似的输出。

原理:首先从训练样本矩阵中选择第一个特征进行划分,使每个子表中该特征的值全部相同(比如第一个特征是男女,则可以划分出两个子表,男表和女表),然后再在每个子表中选择下一个特征按照同样的规则继续划分更小的子表(比如第二个特征是年龄,我可以划分成三个子表(当然根据情况的不同而不同),小于18,大于18小于60,大于60,则在男女表中分别又有三个子表,每个子表下的特征值都相同),不断重复直到所有的特征全部使用完为止,此时便得到叶级子表,其中所有样本的特征值全部相同。

解释:决策树是一种分类方法,用于对样本的特征分类。而分类完成之后,得到的结果是同一类(或者称为表)的所有特征基本相同,然后根据某一类的所有样本通过平均(回归)或者投票(分类)得到一个输出。那么,当有新的待预测样本需要预测输出时,我只需知道样本属于哪个类(表)。

工程优化(剪枝):不必用尽所有的特征,叶级子表中允许混杂不同的特征值,以此降低决策树的层数,在精度牺牲可接受的前提下,提高模型的性能。通常情况下,可以优先选择使信息熵减少量最大的特征作为划分子表的依据。(通俗的讲就是有些特征值并不区分,比如第一个特征是男女,我并不分成两个表,而是放在一个表里,这种情况一般是男女这个特征对输出的影响不大),如何区分有用特征和无用特征或者说影响不大的特征呢?通过信息熵或基尼指数来区分。也可以用PCA和ICA等方法对特征先进行降维操作。

sklearn api

class sklearn.tree.DecisionTreeClassifier()
参数

  • criterion:选值{“gini”, “entropy”},即基尼指数和信息熵,默认‘gini‘
  • splitter: 选值{‘best‘, ‘random‘}, 默认‘best‘,random是为了防止过拟合
  • max_depth: 树的最大深度,如果不给定则会用进所有特征构建树,或者满足参数min_samples_split时停止
  • min_samples_split:节点拆分的最小样本数,可以是int和float,float表示 ceil(min_samples_split * n_samples), 即该小数为总样本的占比
  • min_samples_leaf:每个节点的最小样本数,可以是int和float
  • min_weight_fraction_leaf:float,默认值= 0.0,在所有叶节点处(所有输入样本)的权重总和中的最小加权分数。如果未提供sample_weight,则样本的权重相等
  • max_features :考虑的最大特征数,int,float或{“ auto”,“ sqrt”,“ log2”}
    1. 如果为int,则max_features在每个分割处考虑特征。
    2. 如果为float,max_features则为小数,并 在每次拆分时考虑要素。int(max_features * n_features)
    3. 如果是"auto",则max_features=sqrt(n_features)。
    4. 如果是"sqrt",则max_features=sqrt(n_features)。
    5. 如果为"log2",则为max_features=log2(n_features)。
    6. 如果是None,则max_features=n_features。
  • random_state : 随机种子,int或RandomState。为了防止过拟合,原理不知道
  • max_leaf_nodes:最大的叶子节点数,具体取值依情况调试
  • min_impurity_decrease : 限制信息增益的大小,信息增益小于设定数值的分枝不会发生。
  • min_impurity_split: 在0.19前使用,现由min_impurity_decrease代替
  • class_weight :样本权重
  • ccp_alpha:看不懂
    属性
  • classes_ :标签数组
  • feature_importances_:特征重要性(基于基尼指数和信息熵)
  • max_features_ :模型使用的最大特征数的推断值
  • n_classes_ :样本数
  • n_features_ : 特征数
  • n_outputs_:
  • tree_:tree对象
    方法
  • apply(X[, check_input]):返回X被预测的叶子索引
  • cost_complexity_pruning_path(X, y[, …]):没看懂
  • decision_path(X[, check_input]):返回树中的决策路径
  • fit(X, y[, sample_weight, …]):训练
  • get_depth():获取模型深度
  • get_n_leaves():获取模型叶子数
  • get_params([deep]):获取模型参数
  • predict(X[, check_input]):预测
  • predict_log_proba(X):预测X的对数概率
  • predict_proba(X[, check_input]):预测X的概率
  • score(X, y[, sample_weight]):返回预测y和输出y的正确率占比
  • set_params(params):设置模型参数

验证码识别

前面使用的验证码特征和类别对应过于明显,所以我们选择接口的另一种验证码,即70x25大小的,如下:

虽然同样很简单,但是加入了字符。
至于预处理和数字验证码一样,正常验证码->灰度图->二值化->切割->标注。不过经过测试发现,无论我如何调参,准确率都比较低。看了所有的字符才发现,图片的字符虽然没有倾斜变形但有粗体和细体的区别,而我在标注的时候并没有严格让粗体和细体的样本数一样。而且字符的位置不在图片的中间,字符大小也不一样,有的偏上,有的偏下,有的偏小,有的又偏大。即使重新标注的准确率还是难达到我要的标准。

对于这种分割线和字符边缘明显的验证码来说,我们可以将字符从切割后的图片中提取出来,也就是去掉边缘外的空白,然后都调整到一样的大小。这样就去掉了字符位置和大小对算法的干扰,至于粗体和细体,只要保证这两个的训练样本数量相同就可以了。代码如下:

def img_preprocess(file):
    img1 = Image.open(file)
    pix = np.array(img1)
    pix = (pix > 180) * 255
    width, height = pix.shape
    for i in range(width):
        if np.sum(pix[i]==0):
            xstart = i
            break
    for i in range(width-1, 0, -1):
        if np.sum(pix[i]==0):
            xend = i + 1
            break
    for i in range(height):
        if np.sum(pix[:,i]==0):
            ystart = i
            break
    for i in range(height-1, 0, -1):
        if np.sum(pix[:,i]==0):
            yend = i + 1
            break
    new_pix = pix[xstart:xend, ystart:yend]
    img = Image.fromarray(new_pix).convert('L')
    if new_pix.size != (8, 10):
        img = img.resize((8, 10), resample=Image.NEAREST)
    img.save(file)

接着我们使用决策树重新训练样本并调整参数,我们先看max_depth这个参数,代码如下:

from sklearn.tree import DecisionTreeClassifier
import os
from PIL import Image
import numpy as np
import matplotlib.pyplot as mp

def func(k):
    x = []
    y = []
    for label in os.listdir('train'):
        for file in os.listdir(f'train/{label}'):
            im = Image.open(f'train/{label}/{file}')
            pix = np.array(im)
            pix = (pix > 180) * 1
            pix = pix.ravel()
            x.append(list(pix))
            y.append(label)
    train_x = np.array(x)
    train_y = np.array(y)
    model = DecisionTreeClassifier(max_depth=k)
    model.fit(train_x, train_y)
    x = []
    y = []
    for label in os.listdir('test'):
        for file in os.listdir(f'test/{label}'):
            im = Image.open(f'test/{label}/{file}')
            pix = np.array(im)
            pix = (pix > 180) * 1
            pix = pix.ravel()
            x.append(list(pix))
            y.append(label)

    test_x = np.array(x)
    test_y = np.array(y)

    score = model.score(test_x, test_y)
    return score

if __name__ == "__main__":
    os.chdir('G:\\knn\\字符验证码\\')
    x = list(range(1, 15))
    y = [func(i) for i in x]
    mp.scatter(x, y)
    mp.show()

运行结果:

可以看到当max_depth=8的时候,准确率已经很接近1了,所以我们直接将max_depth取8就行了。既然识别的准确率已经接近1,其他的参数调不调整好像并不重要了,不过因为这是验证码的识别,不容易出现过拟合的情况,在其他情况下,如果准确率接近1就更要去调整随机参数(random_state和splitter)和剪枝参数(min_samples_leaf等)来防止过拟合。我后面也试着调整了一下其他参数,发现模型的准确率变化不大,默认即可。

训练测试数据集:https://www.lanzous.com/i8joo0f

最后,我正在学习一些机器学习的算法,对于一些我需要记录的内容我都会分享到博客和微信公众号(python成长路),欢迎关注。平时的话一般分享一些爬虫或者Python的内容。

原文地址:https://www.cnblogs.com/kanadeblisst/p/12170636.html

时间: 2024-08-07 09:58:05

基于决策树的简单验证码识别的相关文章

验证码识别与生成类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等

以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 六位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数字+小写.数字+大写.数字+大小写等情况. 四位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数字+小写.数字+大写.数字+大小写等情况. 简单验证码识别:验证码类型 : 数字+字母, 纯英文, 纯数字,计算题 英数_验证码识别:纯数字,纯英文,数字+英文 中英数_验证码识别:英文.数

基于SVM的字母验证码识别

基于SVM的字母验证码识别 摘要 本文研究的问题是包含数字和字母的字符验证码的识别.我们采用的是传统的字符分割识别方法,首先将图像中的字符分割出来,然后再对单字符进行识别.首先通过图像的初步去噪.滤波.形态学操作等一系列预处理过程,我们能够将图像中的噪点去除掉.为了将字符分割开来,我们利用Kmeans聚类算法对图像中的像素点聚成五类,分别代表五个字符,结果表明Kmeans算法的聚类准确度能够达到99.2%.对字符分割完成之后,我们采用支持向量机的算法对字符进行识别,通过调节参数能够使得准确率达到

Python3简单验证码识别

这次的需求是自动登录某机构网站, 其验证码很具特色, 很适合做验证码识别入门demo, 先贴主要代码, 其中图片对比使用了编辑距离算法, 脚本使用了pillow库 from PIL import Image import requests import re splitter = re.compile(r'\d{30}') # 分割二值化后的图片 # distance('11110000', '00000000') # 比较两个字符串有多少位不同, 返回不同的位数 def distance(st

简单验证码识别 tessnet2

今天突然间对识别验证码感兴趣,于是网上搜了一下 最简单的是引用tessnet2.dll,然后通过它来识别,代码如下 1 private void button1_Click(object sender, EventArgs e) 2 { 3 string strUrl = @"http://www.gz.gov.cn/sofpro/gecs/common/image.jsp?dt=Thu%20Nov%2024%202011%2017:20:21%20GMT+0800%20(China%20Sta

python 验证码识别示例(四) 简单验证码识别

今天介绍一个简单验证的识别. 主要是标准的格式,没有扭曲和变现.就用 pytesseract 去识别一下. 验证码地址:http://wsxf.mca.gov.cn/zfp/Random.cmd?d=1565452532947 需要识别的验证码是: 识别结果是: 识别率百分之八十.10个有两个错误. 识别代码: #coding:utf-8 from common.contest import * from PIL import Image import pytesseract def recog

python 验证码识别示例(五) 简单验证码识别 » 立即查看

今天介绍一个简单验证的识别. 主要是标准的格式,没有扭曲和变现.就用 pytesseract 去识别一下. 验证码地址:http://wscx.gjxfj.gov.cn/zfp/webroot/xfsxcx.html 需要识别的验证码是: 因为这个验证码有干扰点,所以直接识别的效果非常不好. 首先对验证码进行二值化和降噪. 效果如下: 识别结果: 识别率只有百分之四十,针对这么低的识别率,可以去切割分类,目前这个验证码很容易去切割.提高验证码的识别率问题. 二值化代码: # coding:utf

python 验证码识别示例(三) 简单验证码识别

今天介绍一个简单验证的识别. 主要是标准的格式,没有扭曲和变现.就用 pytesseract 去识别一下. 验证码地址:https://user.www.gov.cn/sso/verifyimg_edit?rd=0.22469390770687414 需要识别的验证码是: 识别结果是: 识别代码是: #coding:utf-8 from common.contest import * from PIL import Image import pytesseract def recognize_c

C#简单验证码码识别

写在最前 最近做一个小玩意需要识别验证码,之前从来没接触过验证码识别这块,这可难到了我.所以,只有三番五次的麻烦度娘帮我找找验证码识别这块的资料.所幸,许多前辈分享的博文帮到了我.最终,完美的把问题解决. 我要识别的验证码属于非常简单的一种,如下图: 1.图片灰度化(把彩色的验证码图片转换成灰色图片) for(int i = 0; i < bmp.Width; i++) { for(int j = 0; j < bmp.Height; j++) { Color color = bmp.GetP

验证码识别之二值化

前言 二值化顾名思义就是将数变成两种值,一般非0即1.而在验证码处理中,如果直接使用灰度图,那么每个像素的值会在0-255,这样肯定会增加计算时间,而二值化后每个像素的值只是0和1. 在前面的简单验证码识别中,我的二值化代码是这样写的:a = (a > 180) * 255,至于这里为什么不乘1而乘255,因为我要显示图片看看效果.如果只是用于算法识别的话,乘1会更好.但是,这里的180也就是二值化的阈值是如何得到的,开始是通过一个一个试然后看效果哪个好就选哪个,因为我们一般只识别某个网站的验证