当前位置: 首页 > 科技观察

太嚣张了!他居然用Python绕过“验证码”

时间:2023-03-19 01:42:28 科技观察

准备工作这里我们使用OpenCV进行图像处理,所以需要安装以下两个库:pip3installopencv-pythonpip3installnumpy代码,包括以下步骤:图像处理:对图像进行降噪和二值化处理。剪切图片:将图片剪切成单个字符并保存。人工标注:将切出的人物图片人工标注为训练集。训练数据:用KNN算法训练的数据。检测结果:使用上一步的训练结果来识别新的验证码。下面一一介绍每一步的过程,并给出具体的代码实现。图片处理先来看看我们要识别的验证码长什么样子:如上图所示,字符都经过了扭曲变形。如果仔细观察,还可以发现图片的中间部分添加了一些颗粒状的噪点。我们先读入图片,将图片转成灰度图。代码如下:importcv2im=cv2.imread(filepath)im_gray=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)经过上面的处理,我们的彩色图片就变成了如下:二值化图片,代码如下:ret,im_inv=cv2.threshold(im_gray,127,255,cv2.THRESH_BINARY_INV)127是我们设置的阈值,大于127的像素值设置为0,小于127的设置为255。处理后的图像变成这样:接下来,我们应用高斯模糊对图像进行去噪。高斯模糊的本质是利用高斯核对图像进行卷积。代码如下:kernel=1/16*np.array([[1,2,1],[2,4,2],[1,2,1]])im_blur=cv2.filter2D(im_inv,-1,kernel)降噪后的图片如下:上图中,一些颗粒状的噪点已经被平滑掉了。去噪后,我们对图像再做一轮二值化:ret,im_res=cv2.threshold(im_blur,127,255,cv2.THRESH_BINARY)现在图像变成这样:好了,接下来我们开始对图像进行裁剪。裁图这一步是所有步骤中最复杂的一步。我们的目标是将初始图片切割成单个字符,并将每个字符保存为灰度图像,如下所示:首先,我们使用OpenCV的findContours提取轮廓:im2,contours,hierarchy=cv2.findContours(im_res,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)我们用一个矩形框住提取出来的轮廓,画成这样:可以看到每个字符都被检测到了。但这只是理想情况。很多情况下,相邻的字符粘在一起会被识别为同一个字符,比如下面这种情况:针对这种情况,我们需要对上图进一步分割。卡字有几种情况,下面一一看怎么处理。①在4个字符识别为3个字符的情况下,从中间开始划分内聚字符轮廓,代码如下:result=[]forcontourincontours:x,y,w,h=cv2.boundingRect(contour)ifw==w_max:#w_max是所有contonurwidthbox_left=np.int0([[x,y],[x+w/2,y],[x+w/2,y+h],[x,y+h]])box_right=np.int0([[x+w/2,y],[x+w,y],[x+w,y+h],[x+w/2,y+h]])result.append(box_left)result.append(box_right)else:box=np.int0([[x,y],[x+w,y],[x+w,y+h],[x,y+h]])result.append(box)划分后,图片变成这样:②4个字符被识别为2个字符,4个字符被识别为2个字符有以下两种情况:是在第一种情况下,对于左右轮廓,只需将它们从中间分开即可。对于第二种情况,包含3个字符的轮廓被水平三等分。具体代码如下:result=[]forcontourincontours:x,y,w,h=cv2.boundingRect(contour)ifw==w_maxandw_max>=w_min*2:#如果两个轮廓之一大于两倍宽度另一方面,我们认为这个轮廓是包含3个字符的轮廓box_left=np.int0([[x,y],[x+w/3,y],[x+w/3,y+h],[x,y+h]])box_mid=np.int0([[x+w/3,y],[x+w*2/3,y],[x+w*2/3,y+h],[x+w/3,y+h]])box_right=np.int0([[x+w*2/3,y],[x+w,y],[x+w,y+h],[x+w*2/3,y+h]])result.append(box_left)result.append(box_mid)result.append(box_right)elifw_max