热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

clean算法_KNN算法实战:验证码的识别

识别验证码的方式很多,如tesseract、SVM等。今天主要学习的是如何使用KNN进行验证码的识别。数据准备本次实验采用的是CSDN的验证码做演练目前接口返回的验证

识别验证码的方式很多,如tesseract、SVM等。今天主要学习的是如何使用KNN进行验证码的识别。

数据准备

本次实验采用的是CSDN的验证码做演练

目前接口返回的验证码共2种:

d01f162a9c19ba384ef719a75e8f2e0d.png

纯数字、干扰小的验证码,简单进行图片去除背景、二值化和阈值处理后,使用kNN算法即可识别。

0e60402e37116738a9d135ce672877fc.png

字母加数字、背景有干扰、图形字符位置有轻微变形,进行图片去除背景、二值化和阈值处理后,使用kNN算法识别

这里选择第二种进行破解。由于两种验证码的图片大小不一样,所以可以使用图片大小来判断哪个是第一种验证码,哪个是第二种验证码。

下载验证码

import requests import uuid from PIL import Image import os url = "http://download.csdn.net/index.php/rest/tools/validcode/source_ip_validate/10.5711163911089325" for i in range(1000): resp = requests.get(url) filename = "./captchas/" + str(uuid.uuid4()) + ".png" with open(filename, 'wb') as f: for chunk in resp.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) f.flush() f.close() im = Image.open(filename) if im.size != (70, 25): im.close() os.remove(filename) else: print(filename)

分割字符

下载过后,就需要对字母进行分割。分割字符还是一件比较麻烦的工作。

灰度化

将彩色的图片转化为灰度图片,便于后面的二值化处理,示例代码:

from PIL import Image file = ".captchas0a4a22cd-f16b-4ae4-bc52-cdf4c081301d.png" im = Image.open(file) im_gray = im.convert('L') im_gray.show()

处理前:

efca026f600c9c8a8970a4fe73fe4452.png

处理后:

c894cf7400d03c254679e21574cfd195.png

二值化

灰度化以后,有颜色的像素点为0-255之间的值。二值化就是将大于某个值的像素点都修改为255,小于该值的修改为0,示例代码:

from PIL import Image import numpy as np file = ".captchas0a4a22cd-f16b-4ae4-bc52-cdf4c081301d.png" im = Image.open(file) im_gray = im.convert('L') # im_gray.show() pix = np.array(im_gray) print(pix.shape) print(pix) threshold = 100 #阈值 pix = (pix > threshold) * 255 print(pix) out = Image.fromarray(pix) out.show()

二值化输出的结果:

edf73464cc0abc0a6e9e65642718f553.png

去除边框

从二值化输出的结果可以看到除了字符,还存在边框,在切割字符前还需要先将边框去除。

border_width = 1

new_pix = pix[border_width:-border_width,border_width:-border_width

字符切割

由于字符与字符间没有存在连接,可以使用比较简单的“投影法”进行字符的切割。原理就是将二值化后的图片先在垂直方向进行投影,根据投影后的极值来判断分割边界。分割后的小图片再在水平方向进行投影。

0a8cd9ab165e09f9e1ff997e5e511b58.png

代码实现:

def vertical_image(image): height, width = image.shape h = [0] * width for x in range(width): for y in range(height): s = image[y, x] if s == 255: h[x] += 1 new_image = np.zeros(image.shape, np.uint8) for x in range(width): cv2.line(new_image, (x, 0), (x, h[x]), 255, 1) cv2.imshow('vert_image', new_image) cv2.waitKey() cv2.destroyAllWindows()

整体代码

from PIL import Image import cv2 import numpy as np import os import uuid def clean_bg(filename): im = Image.open(filename) im_gray = im.convert('L') image = np.array(im_gray) threshold = 100 # 阈值 pix = (image > threshold) * 255 border_width = 1 new_image = pix[border_width:-border_width, border_width:-border_width] return new_image def get_col_rect(image): height, width = image.shape h = [0] * width for x in range(width): for y in range(height): s = image[y, x] if s == 0: h[x] += 1 col_rect = [] in_line = False start_line = 0 blank_distance = 1 for i in range(len(h)): if not in_line and h[i] >= blank_distance: in_line = True start_line = i elif in_line and h[i] = blank_distance: in_line = True start_line = i elif in_line and i == len(h)-1: row_rect = (start_line, i) elif in_line and h[i] threshold) * 255 border_width = 2 new_image = pix[border_width:-border_width, border_width:-border_width] return new_image def split(filename): image = clean_bg(filename) col_rect = get_col_rect(image) for cols in col_rect: block_image = get_block_image(image, cols) if block_image is not None: new_image_filename = 'letters/' + str(uuid.uuid4()) + '.png' cv2.imwrite(new_image_filename, block_image) if __name__ == '__main__': for filename in os.listdir('captchas'): current_file = 'captchas/' + filename split(current_file) print('split file:%s' % current_file)

数据集准备

在完成图像切割后,需要做将切分的字母建立由标签的样本。即将切分后的字符梳理到正确的分类中。比较常见的方式是人工梳理。

由于图像比较多,这里使用使用Tesseract-OCR进行识别。

官方项目地址: https://github.com/tesseract-ocr/tesseract

Windows安装包地址: https://github.com/UB-Mannheim/tesseract/wiki

Tesseract-OCR的安装

下载完安装包后,直接运行安装即可,比较重要的是环境变量的设置。

将安装目录(D:Program Files (x86)Tesseract-OCR)添加进PATH

新建TESSDATA_PREFIX系统变量,值为tessdata 文件夹的路径(D:Program Files (x86)Tesseract-OCRessdata)

安装Python包pytesseract(pip install pytesseract)

Tesseract-OCR的使用

使用起来非常的简单,代码如下:

from PIL import Image import pytesseract import os def copy_to_dir(filename): image = Image.open(filename) code = pytesseract.image_to_string(image, config="-c tessedit" "_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" " --psm 10" " -l osd" " ") if not os.path.exists("dataset/" + code): os.mkdir("dataset/" + code) image.save("dataset/" + code + filename.replace("letters", "")) image.close() if __name__ == "__main__": for filename in os.listdir('letters'): current_file = 'letters/' + filename copy_to_dir(current_file) print(current_file)

由于Tesseract-OCR识别的准确率非常的低,完全不能使用,放弃~,还是需要手工整理。

图片尺寸统一

在完成人工处理后,发现切割后的图片大小不一。在字符识别前需要对图片进行的尺寸进行统一。

具体实现方法:

import cv2 def image_resize(filename): img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) #读取图片时采用单通道 print(img) if img.shape[0] != 10 or img.shape[1] != 6: img = cv2.resize(img, (6, 10), interpolation=cv2.INTER_CUBIC) print(img) cv2.imwrite(filename, img)

使用cv2.resize时,参数输入是 宽×高×通道,这里使用的时单通道的,interpolation的选项有:

INTER_NEAREST 最近邻插值

INTER_LINEAR 双线性插值(默认设置)

INTER_AREA 使用像素区域关系进行重采样。 它可能是图像抽取的首选方法,因为它会产生无云纹理的结果。 但是当图像缩放时,它类似于INTER_NEAREST方法。

INTER_CUBIC 4×4像素邻域的双三次插值

INTER_LANCZOS4 8×8像素邻域的Lanczos插值

另外为了让数据更加便于利用,可以将图片再进行二值化的归一。具体代码如下:

import cv2 import numpy as np def image_normalize(filename): img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) #读取图片时采用单通道 if img.shape[0] != 10 or img.shape[1] != 6: img = cv2.resize(img, (6, 10), interpolation=cv2.INTER_CUBIC) normalized_img = np.zeros((6, 10)) # 归一化 normalized_img = cv2.normalize(img, normalized_img, 0, 1, cv2.NORM_MINMAX) cv2.imwrite(filename, normalized_img)

归一化的类型,可以有以下的取值:

NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。

NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)

NORM_L1 : 归一化数组的L1-范数(绝对值的和)

NORM_L2: 归一化数组的(欧几里德)L2-范数

字符识别

字符图片 宽6个像素,高10个像素 ,理论上可以最简单粗暴地可以定义出60个特征:60个像素点上面的像素值。但是显然这样高维度必然会造成过大的计算量,可以适当的降维。比如:

每行上黑色像素的个数,可以得到10个特征

每列上黑色像素的个数,可以得到6个特征

from sklearn.neighbors import KNeighborsClassifier import os from sklearn import preprocessing import cv2 import numpy as np import warnings warnings.filterwarnings(module='sklearn*', action='ignore', category=DeprecationWarning) def get_feature(file_name): img = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE) # 读取图片时采用单通道 height, width = img.shape pixel_cnt_list = [] for y in range(height): pix_cnt_x = 0 for x in range(width): if img[y, x] == 0: # 黑色点 pix_cnt_x += 1 pixel_cnt_list.append(pix_cnt_x) for x in range(width): pix_cnt_y = 0 for y in range(height): if img[y, x] == 0: # 黑色点 pix_cnt_y += 1 pixel_cnt_list.append(pix_cnt_y) return pixel_cnt_list if __name__ == "__main__": test = get_feature("dataset/K/04a0844c-12f2-4344-9b78-ac1d28d746c0.png") category = [] features = [] for dir_name in os.listdir('dataset'): for filename in os.listdir('dataset/' + dir_name): category.append(dir_name) current_file = 'dataset/' + dir_name + '/' + filename feature = get_feature(current_file) features.append(feature) # print(current_file) le = preprocessing.LabelEncoder() label = le.fit_transform(category) model = KNeighborsClassifier(n_neighbors=1) model.fit(features, label) predicted= model.predict(np.array(test).reshape(1, -1)) print(predicted) print(le.inverse_transform(predicted))

这里直接使用了sklearn中的KNN方法



推荐阅读
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 前言:拿到一个案例,去分析:它该是做分类还是做回归,哪部分该做分类,哪部分该做回归,哪部分该做优化,它们的目标值分别是什么。再挑影响因素,哪些和分类有关的影响因素,哪些和回归有关的 ... [详细]
  • c语言调用链表,c语言链表的实现
    本文目录一览:1、C语言创建链表,函数调用部分 ... [详细]
  • 表里|层面_ShardingJDBC第一篇:分库分表
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了ShardingJDBC第一篇:分库分表相关的知识,希望对你有一定的参考价值。文章目录 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了一个Python函数same_set,用于判断两个相等长度的数组是否包含相同的元素。函数会忽略元素的顺序和重复次数,如果两个数组包含相同的元素,则返回1,否则返回0。文章还提供了函数的具体实现代码和样例输入输出。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • 做实验需要重命名数据集的名字,有几个容易踩坑的地方和小技巧,总结一下importospathfilelistos.listdir(path)#文件夹路 ... [详细]
  • python3下载mapbox矢量切片通过观察mapbox的页面开发者工具里的network可以发现,打开矢量切片和字体切片pbf和prite图标的链接, ... [详细]
  • Thisissuewasoriginallyopenedbyashashicorp/terraform#5664.Itwasmigratedhe ... [详细]
  • 装饰模式(Deocrator)     动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。    所谓装饰,就是一些对象给主题 ... [详细]
  • 调用百度ocr的API,python简易版本
    https:www.jianshu.compe10dc43c38d01.注册百度云注册账号https:cloud.baidu.com?fromconsole管理应用https:co ... [详细]
author-avatar
翔未央图_971
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有