基于Python爬虫+KNN数字验证码识别系统——机器学习算法应用(含全部工程源码)+训练数据集

news2024/11/24 7:03:29

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
    • Python 环境
  • 模块实现
    • 1. 数据爬取
    • 2. 去噪与分割
    • 3. 模型训练及保存
    • 4. 准确率验证
  • 系统测试
  • 工程源代码下载
  • 其它资料下载


在这里插入图片描述

前言

本项目利用Python爬虫技术,通过网络爬取验证码图片,并通过一系列的处理步骤,包括去噪和分割,以实现对验证码的识别和准确性验证。

首先,我们使用Python爬虫技术自动从目标网站上获取验证码图片。这些验证码通常是为了防止机器人自动访问或提交表单而设计的。通过爬虫技术,我们可以获取这些验证码图片用于后续处理。

接下来,我们对获取的验证码图片进行去噪和分割处理。去噪操作可以帮助去除图片中的干扰信息,使得验证码更清晰易读。分割操作将验证码中的每个字符单独提取出来,以便后续进行识别。

随后,我们采用KNN算法(K-Nearest Neighbors)来训练一个模型。KNN算法是一种常用的监督学习算法,可以根据样本的特征和标签来进行分类。我们将使用KNN算法对分割后的验证码字符进行训练,以便模型能够识别不同的字符。

最后,我们对训练好的模型进行准确率验证。通过将一部分已知标签的验证码图片输入模型,我们可以得到模型的预测结果。将预测结果与实际标签进行比较,可以计算出模型的准确率,从而评估模型的性能。

这个项目的目标是通过爬虫技术和图像处理算法,实现对验证码图片的自动识别和准确率验证。它可以应用于需要处理大量验证码的场景,如自动化测试、数据采集等。通过训练和验证模型的过程,我们可以不断提升验证码识别的准确性和稳定性,提高验证码处理的效率。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分主要为 Python 环境

Python 环境

需要Python 2.7配置,在Windows环境下下载Anaconda完成Python所需的配置,下 载地址为https://www.anaconda.com/,也可以下载虚拟机在Linux环境下运行代码。

模块实现

本项目包括4个模块:数据爬取、去噪与分割、模型训练及保存、准确率验证,下面分别介绍各模块的功能及相关代码。

1. 数据爬取

本部分用request库爬虫抓取验证码1200张,并做好标注。相关代码如下:

from __future__ import unicode_literals
import requests
import time
if __name__ == "__main__":
    #获取图片总数设置number
    number = 100
    for num in range(number):
        img_url='http://run.hbut.edu.cn/Account/LogOn?ReturnUrl=%2f '
        data={'timestamp':unicode(long(time.time()*1000))}
        #print (img_url)
        res = requests.get(img_url,params=data)
#这是一个get请求,获取图片资源
       with open("./download_image/%d.jpg" % num, "wb") as f:  
#将图片保存在本地
            f.write(res.content)
            print("%d.jpg" % num + "获取成功")

在这里插入图片描述

2. 去噪与分割

图片爬取成功后进行去噪与分割。

1)去除背景噪声

转换成灰度图后对图片进行分割,去掉边框和部分噪声,分成4张图,统计每张图的灰度直方图(自己设置bins),找到第二大对应的像素范围(即某一-像素范围内像素数第二多,对应的像素范围。像素最多的应该是白色,空白处),取像素范围中位数模式,然后保留(modebiases)的像素,去除大部分噪声。

def del_noise(im_cut):
    bins = 16
    num_gray = math.ceil(256 / bins)
#函数返回大于或等于一个给定数字的最小整数
    hist = cv2.calcHist([im_cut], [0], None, [bins], [0, 256])
    lists = []
    for i in range(len(hist)): 
    #print hist[i][0]
        lists.append(hist[i][0])
    second_max = sorted(lists)[-2]
    #查找第二多像素,最多的是验证码空白
    bins_second_max = lists.index(second_max)
        #取像素范围中位数mode,保留(mode±biases)的像素
    mode = (bins_second_max + 0.5) * num_gray
    for i in range(len(im_cut)):
        for j in range(len(im_cut[0])):
    #print im_cut[i][j]
       if im_cut[i][j] < mode - 15 or im_cut[i][j] > mode + 15:]
    #不在中位数附近的设为白(255)
                im_cut[i][j] = 255
    return im_cut

2)图片分割

分割1200张已标注好的图片,得到4800张子图片。相关代码如下:

def cut_image(image, num, img_name):
   #image = cv2.imread('./img/8.jpg')
   #将BGR格式图片转换成灰度图片
    im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
   #im_cut_real = im[8:47, 28:128]
    im_cut_1 = im[8:47, 27:52]
    im_cut_2 = im[8:47, 52:77]
    im_cut_3 = im[8:47, 77:102]
    im_cut_4 = im[8:47, 102:127]
    im_cut = [im_cut_1, im_cut_2, im_cut_3, im_cut_4]
    for i in range(4):
        im_temp = del_noise(im_cut[i])
     #将图片分割为4个
     cv2.imwrite('./img_train_cut/'+str(num)+ '_' + str(i)+'_'+img_name[i]+'.jpg', im_temp)
if __name__ == '__main__':
    img_dir = './img'
    img_name = os.listdir(img_dir)  #列出文件夹下所有的目录与文件
    for i in range(len(img_name)):
        path = os.path.join(img_dir, img_name[i])
        image = cv2.imread(path)
        name_list = list(img_name[i])[:4]
        #name = ''.join(name_list)
        cut_image(image, i, name_list)
        print '图片%s分割完成' % (i)
    print u'*****图片分割预处理完成!*****'

分割图片成功,如下图所示:

在这里插入图片描述

3. 模型训练及保存

处理数据后拆分训练集和测试集,训练并保存。相关代码如下:

_image(image, num, img_name):
   #image = cv2.imread('./img/8.jpg')
   #将BGR格式图片转换成灰度图片
    im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
   #im_cut_real = im[8:47, 28:128]
    im_cut_1 = im[8:47, 27:52]
    im_cut_2 = im[8:47, 52:77]
    im_cut_3 = im[8:47, 77:102]
    im_cut_4 = im[8:47, 102:127]
    im_cut = [im_cut_1, im_cut_2, im_cut_3, im_cut_4]
    for i in range(4):
        im_temp = del_noise(im_cut[i])
     #将图片分割为4个
     cv2.imwrite('./img_train_cut/'+str(num)+ '_' + str(i)+'_'+img_name[i]+'.jpg', im_temp)
if __name__ == '__main__':
    img_dir = './img'
    img_name = os.listdir(img_dir)  #列出文件夹下所有的目录与文件
    for i in range(len(img_name)):
        path = os.path.join(img_dir, img_name[i])
        image = cv2.imread(path)
        name_list = list(img_name[i])[:4]
        #name = ''.join(name_list)
        cut_image(image, i, name_list)
        print '图片%s分割完成' % (i)
    print u'*****图片分割预处理完成!*****'
8.3.3 模型训练及保存
import numpy as np
from sklearn import neighbors
import os
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.externals import joblib
import cv2
if __name__ == '__main__':
    #读入数据
    data = []
    labels = []
    img_dir = './img_train_cut'
    img_name = os.listdir(img_dir)
    #number = ['0','1', '2','3','4','5','6','7','8','9']
    for i in range(len(img_name)):
        path = os.path.join(img_dir, img_name[i])
        #cv2读进来的图片是RGB3维的,转成灰度图,将图片转化成1维
        image = cv2.imread(path)
        im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        image = im.reshape(-1)
        data.append(image)
        y_temp = img_name[i][-5]
        labels.append(y_temp)
    #标签规范化
    y = LabelBinarizer().fit_transform(labels)
    x = np.array(data)
    y = np.array(y)
    #拆分训练数据与测试数据
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
    #训练KNN分类器
    clf = neighbors.KNeighborsClassifier()
    clf.fit(x_train, y_train)
    #保存分类器模型
    joblib.dump(clf, './knn.pkl')
    #测试结果打印
    pre_y_train = clf.predict(x_train)
    pre_y_test = clf.predict(x_test)
    class_name = ['class0', 'class1', 'class2', 'class3', 'class4', 'class5', 'class6', 'class7', 'class8', 'class9']
    print classification_report(y_train, pre_y_train, target_names=class_name)
    print classification_report(y_test, pre_y_test, target_names=class_name)
    #clf = joblib.load('knn.pkl')
    #pre_y_test = clf.predict(x)
    #print pre_y_test
    #print classification_report(y, pre_y_test, target_names=class_name)

模型保存后,可以被重新使用,也可以移植到其他环境中使用。

4. 准确率验证

用验证码原图(4个数字)来测试准确率,相关代码如下:

from __future__ import division
import cv2
import math
import numpy as np
import os
from sklearn.externals import joblib
def del_noise(im_cut):
  '''
  变量bins:灰度直方图bin的数目
  num_gray:像素间隔
  方法:1.找到灰度直方图中像素第二多对应的像素,即second_max,因为图像空白处比较多,所以第一多的应该是空白,第二多的是想要的内容。2.计算mode。3.除了mode附近,全部变为空白。
  '''
    bins = 16
    num_gray = math.ceil(256 / bins)
    hist = cv2.calcHist([im_cut], [0], None, [bins], [0, 256])
    lists = []
    for i in range(len(hist)):
        #print hist[i][0]
        lists.append(hist[i][0])
        #将 hist 列表添加到 lists
    second_max = sorted(lists)[-2]
#查找第二多像素,最多的是验证码的空白
    bins_second_max = lists.index(second_max)
#取像素范围中位数mode,然后保留(mode±biases)的像素
    mode = (bins_second_max + 0.5) * num_gray
    for i in range(len(im_cut)):
        for j in range(len(im_cut[0])):
           if im_cut[i][j]<mode - 15 or im_cut[i][j] > mode + 15:
                # print im_cut[i][j]
                im_cut[i][j] = 255
                #不在中位数附近的设为白(255)
    return im_cut
def predict(image, img_name):
    #image = cv2.imread('./img/8.jpg')
    im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    #将BGR格式转换成灰度图片
    #im_cut_real = im[8:47, 28:128]
    im_cut_1 = im[8:47, 27:52]
    im_cut_2 = im[8:47, 52:77]
    im_cut_3 = im[8:47, 77:102]
    im_cut_4 = im[8:47, 102:127]
    im_cut = [im_cut_1, im_cut_2, im_cut_3, im_cut_4]
    pre_text = []
    for i in range(4):
        #图片转换成1维后,再转换成2维的输入变量x
        im_temp = del_noise(im_cut[i])
        #print type(im_temp)
        image = im_temp.reshape(-1)
        #print image.shape
        tmp = []
        tmp.append(list(image))
        x = np.array(tmp)
        pre_y = clf.predict(x)
        pre_y = np.argmax(pre_y[0])
        pre_text.append(str(pre_y))
    #print pre_text
    pre_text = ''.join(pre_text)
    if pre_text != img_name:
print'label:%s'%(img_name),'predict:%s'%(pre_text),'\t','false'
        return 0
    else:
        print 'label:%s'%(img_name),'predict:%s'%(pre_text)
        return 1
if __name__ == '__main__':
    img_dir = './img_test'
    img_name = os.listdir(img_dir)  #列出文件夹下所有的目录与文件
    right = 0
    global clf
    clf = joblib.load('knn.pkl')
    for i in range(len(img_name)):
        path = os.path.join(img_dir, img_name[i])
        image = cv2.imread(path)
        name_list = list(img_name[i])[:4]
        name = ''.join(name_list)
        pre = predict(image, name)
        right += pre
    accuracy = (right/len(img_name))*100
 print u'准确率为:%s%%,一共%s张验证码,正确:%s,错误:%s'%(accuracy,len(img_name),right,len(img_name)-right)

系统测试

测试结果精度达到99%以上,如下图所示。

在这里插入图片描述

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/723395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT5项目程序打包成可执行exe程序(绿色版)

一、QT在release模式下编译生成.exe 二、然后新建一个空白文件夹package&#xff0c;再将在release模式下生成的.exe文件复制到新建的文件夹中package。 三、打开QT5的命令行&#xff08;选择项目所使用的的环境&#xff09; 查找项目使用环境 打开命令行 四、在命令行输入命令…

马斯克:未来会涌现大量机器人,与人类比例有望超过1比1

在世界人工智能大会上&#xff0c;特斯拉的马斯克通过网络发表了视频演讲&#xff0c;涵盖了特斯拉人形机器人Optimus、自动驾驶和人工智能等话题。他赞扬了中国的AI产业&#xff0c;并表示中国在决心和实施方面非常出色&#xff0c;包括AI产业发展在内。 特斯拉的人型机器人目…

数学美学:探索“既不是最小值也不是最大值”的魅力

本篇博客会讲解力扣“2733. 既不是最小值也不是最大值”的解题思路&#xff0c;这是题目链接。 本题的思路是&#xff1a; 若数组只有2个元素&#xff0c;显然任意一个元素不是最小值就是最大值。若数组有3个以上的元素&#xff0c;由于提示中的第3点&#xff1a;数组中的所有…

中国首家外资独资期货公司,摩根大通期货持仓龙虎榜的持仓动向和盈亏状况

摩根大通期货&#xff0c;为什么持仓量长期排在期货龙虎榜前列 摩根大通是一家全球领先的金融服务机构&#xff0c;拥有超过200年的历史&#xff0c;业务遍及全球100多个国家和地区。这个期货公司比较神秘&#xff0c;只有上海一个营业部&#xff0c;在业务方向上以机构客户为服…

YOLOv5、YOLOv8改进教程:7. 添加SK-Net注意力机制

论文地址:Selective Kernel NetworksGithub:https://github.com/implus/SKNet如果你是深度学习小白,阅读本文前建议先学习一下 📖《新手入门深度学习》如果你有一定基础,但是缺乏实战经验,可通过 📖《深度学习100例》 补齐基础另外,我们正在通过 🔥365天深度学习训…

ATM模拟-管理员登录用户查询

项目来源&#xff1a;新星计划2023【JavaWeb实现ATM机存取款项目实战】 学习方向报名入口-CSDN社区 目录 管理员登录 管理员登录逻辑 管理员登录主程序 功能实现 代码如下&#xff1a; 用户信息封装 实现功能 代码实现&#xff1a; 业务层代码具体实现 功能实现 业…

linux查看内存总结

参考博客&#xff1a; https://www.atlantic.net/vps-hosting/find-top-10-running-processes-by-memory-and-cpu-usage/ 最简单的命令 free -g 查看还有多少可用的内存 但是有的时候这个提供的信息实在是太少了&#xff0c;例如我今天发现服务器上可用的内存只有50G, 我想知…

第2章 SSD主控和全闪存阵列

通过第一章可知&#xff0c;SSD主要由两大模块组成&#xff1a;主控和闪存介质。其中&#xff0c;主控的作用包括&#xff1a; &#xff08;1&#xff09;实现标准主机接口与主机通信&#xff1b; &#xff08;2&#xff09;实现与闪存的通信&#xff1b; &#xff08;1&#x…

算法与数据结构-队列

文章目录 什么是队列队列和栈的区别 队列的类型顺序队列链式队列循环队列阻塞队列并发队列 总结 什么是队列 队列跟栈一样&#xff0c;也是一种操作受限的线性表数据结构。不过&#xff0c;队列是先进者先出。 队列和栈的区别 栈只支持两个基本操作&#xff1a;入栈 push()和出…

【Kafka】Kafka consumer lag 为负数

前言 最近对Kafka 集群部署了 Kafka_exporter 监控&#xff0c;并集成了 granfana 图标展示。 发现 Consumer Group Lag 有时候为负数。 于是进行一番查询&#xff0c;并总结整理下。 具体情形 从下图可以看出&#xff0c;consumer group 值有时候出现负数的情况。 具体原…

Python 使用 pyc 解决明文密钥问题

文章目录 前言1. pyc 介绍2. py 代码编译2.1 使用命令行编译2.2 使用代码编译 3. 避免名为密钥案例3.1 创建密钥存储代码文件3.2 编译密钥代码3.3 调用密钥代码 前言 写代码过程中&#xff0c;可能遇到一些敏感信息不想明文暴露在代码中的情况&#xff0c;本篇文章介绍使用 py…

多tab之间的sessionStorage能不能直接共享访问?

首先&#xff0c;先理解下一个页面的sessionStorage是怎么回事。 1、当前A页面有sessionStorage值为123&#xff0c;我F5强刷页面&#xff0c;sessionStorage值还在不在&#xff1f; 答&#xff1a;在。 2、当前A页面有sessionStorage值为123&#xff0c;我复制A页面地址在浏览…

浏览器console发送get或post请求

浏览器console发送get或post请求 get请求 var url "http://******:8080/base/testapi/testcurl?urlhttps%3A%2F%2Fwww.baidu.com%2F"; var xhr new XMLHttpRequest(); xhr.open("GET", url, true); xhr.setRequestHeader("Content-Type", &…

RPG++——游戏编辑器的开发

完整资料进入【数字空间】查看——baidu搜索"writebug" 随着当下电子设备的普及以及人们对娱乐需求的上升&#xff0c;电子游戏逐渐走进千家万户。RPG&#xff08;角色扮演&#xff09;游戏作为最经典的游戏种类之一&#xff0c;因其游戏形式多样&#xff0c;自由度…

矢量数据库对比和选择指南

矢量数据库是为实现高维矢量数据的高效存储、检索和相似性搜索而设计的。使用一种称为嵌入的过程&#xff0c;将向量数据表示为一个连续的、有意义的高维向量。 本文将研究存储/检索向量数据和执行相似性搜索的实用方法&#xff0c;在我们深入研究之前&#xff0c;首先先介绍矢…

改进 Elastic Stack 中的信息检索:提高搜索相关性的步骤

作者&#xff1a;Grgoire Corbire, Quentin Herreros, Thomas Veasey 自 8.0 和用于文本嵌入的第三方自然语言处理 (NLP) 模型发布以来&#xff0c;Elastic Stack 的用户可以访问各种模型来嵌入其文本文档并使用矢量搜索执行基于查询的信息检索。 考虑到所有这些组件及其参数…

Rust 第二天---Rust基础总结

之前已经配置好了Rust的环境,那学习一门语言最开始就是去掌握了解它的基本语法.其实Rust的语法和大多编程语言没什么差别,熟悉C的应该很容易上手,所以今天就快速过一遍基础. 1. 变量与常量 变量应该是编程中最常用到的,但是Rust与其他语言不同的是在声明变量的时候必须说明这…

vue最强table vxe-table 虚拟滚动列表 前端导出

最近遇到个问题。后台一次性返回2万条列表数据。 并且需求要求所有数据必须全部展示&#xff0c;不能做假分页&#xff08;不能优化了&#xff09;。 这些数据的直接来源就是CS客户端。 他们做CS客户端就是一次性加载几万条数据不分页&#xff08;说这是客户的要求&#xff…

android_mars老师_定位_获取最佳的provider

结果展示 ManiActivity package com.example.locationmanager2;import androidx.appcompat.app.AppCompatActivity;import android.content.Context; import android.location.Criteria; import android.location.LocationManager; import android.os.Bundle; import android.…

开放式耳机对耳朵伤害大吗?开放式耳机是什么意思?

​今天来跟大家一起聊聊&#xff0c;开放式耳机对耳朵伤害大不大&#xff0c;还有就是开放式耳机到底是什么类型的耳机&#xff0c;且开放式耳机有哪些比较好用的... 开放式耳机对耳朵伤害大吗&#xff1f; 开放式耳机对耳机的伤害是比较小的&#xff0c;传统入耳式耳机佩戴久了…