验证码识别过程中切割图片的几种方案

news/2024/12/28 21:45:10/

目录

方案一:图片均分

方案二:寻找轮廓并截取

方案三:聚类算法

方案四:垂直投影法

源码下载


在用机器学习识别验证码的过程中,我们通常会选择把验证码中的各个字符切割出来然后单独识别,切割质量会直接影响识别精度。在本节我们就来看下如何去切割一张验证码图片。

方案一:图片均分

这种方案实现起来很简单,但只能针对一些简单的验证码,比如下面这种。这类验证码有一个特点:字符占据固定的图片宽度且位置保持不变。

 代码编写如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt# 读取图片
img = cv.imread("cut1.png")# 灰度化
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 高斯模糊
img_gaussian = cv.GaussianBlur(img_gray, (9, 9), 0)# 二值化
ret, img_threshold = cv.threshold(img_gaussian, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)# 腐蚀处理
kernel = np.ones((3, 3), np.float32)
img_erode = cv.erode(img_threshold, kernel)# 切割图像,均分成6块
height, width = img_erode.shape
x_gap = width // 6
for i in range(1, 5):roi = img_erode[0:height, i*x_gap:(i+1)*x_gap]plt.subplot(1, 4, i)plt.axis("off")plt.imshow(roi, cmap="gray")
plt.show()

运行结果如下:

方案二:寻找轮廓并截取

我们可以用opencv-python的findContours()方法找到各个字符的轮廓范围,然后从图片上截图下来。采用这种方案的话,我们需要尽量将图片中的噪点和线条干扰去掉,否则返回的可能就不是字符轮廓,而是一些干扰点线的轮廓。现在我们用方案二切割以下验证码图片。

 代码编写如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt# 读取图片
img = cv.imread("cut2.png")# 灰度化
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 高斯模糊
img_gaussian = cv.GaussianBlur(img_gray, (1, 1), 0)# 二值化
ret, img_threshold = cv.threshold(img_gaussian, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)# 腐蚀处理
kernel = np.ones((1, 1), np.float32)
img_erode = cv.erode(img_threshold, kernel)# 寻找字符轮廓并截取
cnts, hiers = cv.findContours(img_erode, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key=lambda x: cv.boundingRect(x)[0])    # 根据罗阔的x坐标从左到右排列
total_num = len(cnts)
for i, cnt in enumerate(cnts):x, y, w, h = cv.boundingRect(cnt)roi = img_erode[y:y+h, x:x+w]plt.subplot(1, total_num, i+1)plt.imshow(roi, cmap="gray")
plt.show()

运行结果如下:

 

方案三:聚类算法

通过聚类算法将各个字符分组,这种方案的稳定性不高,但有时候能够带来很大的惊喜。我们来看下这张验证码图片。

很明显不能对其进行均等分割操作,寻找轮廓的话会返回0、D、KJ这三个轮廓,而不是0、D、K、J。

注:可以将0、D、KJ这三个轮廓合并起来,然后再均分成4块。这是新的一种方案,可以有效解决自负粘连问题,不过各字符字体大小不同的话,效果就不怎么好了。

 

我们尝试用聚类算法分割下这种验证码,代码编写如下。

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans# 读取图片
img = cv.imread("cut3.png")# 灰度化
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 高斯模糊
img_gaussian = cv.GaussianBlur(img_gray, (5, 5), 0)# 二值化
ret, img_threshold = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)# 腐蚀处理
kernel = np.ones((3, 3), np.float32)
img_erode = cv.erode(img_threshold, kernel)# 用聚类算法切割
data = []
rows, cols = img_erode.shape
for i in range(rows):for j in range(cols):if img_erode[i, j] == 255:data.append((i, j))data = np.array(data)
model = KMeans(n_clusters=4)
model.fit(data)
print(sorted(model.cluster_centers_[:, 1]))  # 从小到大打印出各个聚类中心点的x坐标plt.scatter(data[:, 1], data[:, 0], c=model.labels_, cmap="brg")
ax = plt.gca()
ax.xaxis.set_ticks_position('top')
ax.invert_yaxis()
plt.show()

运行结果如下:

各个聚类中心点的x坐标显示如下:

有了这几个中心点的坐标,我们就可以成功截取各个字符。

方案四:垂直投影法

垂直投影法就是将图像上各列符合条件的点都下沉到图片底部,符合条件的点越多,那堆起来的高度也就越高。正常来说,在一个字符的两边,符合条件的点会比字符中间的点要少一些,通过这个原理我们就大概可以知道字符边界了。我们试着用垂直投影法分割以下验证码。

编写代码如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt# 读取图片
img = cv.imread("cut3.png")# 灰度化
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 高斯模糊
img_gaussian = cv.GaussianBlur(img_gray, (5, 5), 0)# 二值化
ret, img_threshold = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)# 腐蚀处理
kernel = np.ones((3, 3), np.float32)
img_erode = cv.erode(img_threshold, kernel)# 使用垂直投影法
rows, cols = img_erode.shape
data = []
for i in range(cols):data.append(0)for j in range(rows):if img_erode[j, i] == 255:data[i] += 1for i in range(cols):plt.bar(i, data[i], color="black")
plt.show()

运行结果如下:

横坐标的值表示图像某一列的x坐标,纵坐标表示该列上符合条件的点。从这个柱状图中我们可以明显看到切割点,在程序中我们可以循环各个x坐标,并比较其两边的值来判断该x坐标是否是我们要找的目标点。

 

源码下载

链接:https://pan.baidu.com/s/1PQfevSMvvN8d_vDeN_5hGw  

密码:1cj4


http://www.ppmy.cn/news/42450.html

相关文章

Leetcode.2521 数组乘积中的不同质因数数目

题目链接 Leetcode.2521 数组乘积中的不同质因数数目 Rating : 1413 题目描述 给你一个正整数数组 nums,对 nums所有元素求积之后,找出并返回乘积中 不同质因数 的数目。 注意: 质数 是指大于 1 且仅能被 1 及自身整除的数字。…

linux替换jar中的文件(小修改,大修改还是整包发布稳妥)

当我们上线某个应用发现有个小bug需要修改,而且改动的地方并不是很多,比如,修改application.yml文件或者替换几个class文件,此时如果找到源文件修改后重新打包替换重启有点繁琐,就可以使用此方式修改。 目录 修改配置文件 修改class文件 附录:jar的命令 修改配置文件 …

一文快速回顾 Servlet、Filter、Listener

什么是Servlet? 前置知识: Web 服务器:可以指硬件上的,也可以指软件上的。从硬件的角度来说, Web 服务器指的就是一台存储了网络服务软件的计算机;从软件的角度来说, Web 服务器指的是一种软件…

【Python搞笑游戏】因蔡徐坤打篮球动作超火,被某程序员写成了一款游戏,画面美到不敢看,成功学到了精髓~(附源码免费)

导语 之前网络最火的梗,非“C徐坤打篮球”莫属。个人感觉,只有多年前的“春哥纯爷们”堪与匹敌! 虽然说C徐坤打篮球是一个老梗了,但是确实非常搞笑,今天就跟着小编一起来回忆一下吧! “我是练习两年半的…

creator-assetbundle分包

title: creator-assetbundle分包 categories: Cocos2dx tags: [creator, 分包, assetbundle] date: 2023-04-10 15:55:22 comments: false mathjax: true toc: true creator-assetbundle分包 前篇 Asset Bundle 介绍 - https://docs.cocos.com/creator/manual/zh/asset/bundle…

【论文笔记】CRN: Camera Radar Net for Accurate, Robust, Efficient 3D Perception

原文链接:https://arxiv.org/abs/2304.00670 1. 引言 本文提出两阶段融合方法CRN,能使用相机和雷达生成语义丰富且位置精确的BEV特征。具体来说,首先将图像透视特征转换到BEV下,该步骤依赖雷达,称为雷达辅助的视图变换…

【CSS】绝对定位元素设置 水平 / 垂直 居中 ( 绝对定位元素居中设置 - 先偏移 50% 再回退子元素一半尺寸 | 绝对定位居中设置 )

文章目录一、问题提出二、绝对定位 居中设置1、设置固定尺寸2、先偏移50%再回退固定值三、绝对定位元素 水平 / 垂直 居中一、问题提出 绝对定位 不能通过 设置 margin: auto; 样式的方式 , 设置盒子模型水平居中 ; 相对定位 的 盒子模型 , 并没有脱离标准流限制 , 仍然可以使…

2023年全国最新二级建造师精选真题及答案50

百分百题库提供二级建造师考试试题、二建考试预测题、二级建造师考试真题、二建证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 35.下列情形中,可以引起诉讼时效中断的有()。 A.权利人申…