近日某众打码平台被跑路的消息一出,脚本圈中一片哗然(我并不是脚本圈的,只是喜欢看群里人吹逼而已 ),仿佛再也听不到那句熟悉的广告语了。这也预示着,第三方打码平台不靠谱了。但打码功能有时候又必不可少,这时候怎么办呢?当然是自己自己动手丰衣足食啦!最近工作不是很忙,准备撸一个用Python识别验证码的系列文章,该系列计划囊括各种时下比较流行的验证码形式,如滑块、四则运算、点选、手势、空间推理、谷歌等。已经跑通了的所有代码都放在了我的知识星球上,需要的话请自取。话不多说,开撸!

让你选出面积最大的区域,不得不说,验证码真的是越来越卷了,越来越花了。

不过这吊验证码仿佛图片不多,背景好像就那么几种,也就那些线会变来变去,而且线的颜色相对于背景来说区别还是挺大的。所以大致思路就是想办法把线和背景分离开来,然后做轮廓检测,把面积最大的轮廓找出来并计算出轮廓的质心就ojbk了。
1.线的颜色都比较明亮,因此这里把图转成HSV颜色空间,并单独将V通道拿出来用
原图:

V通道图:

2.做个伽马变换,把越亮的地方搞的越亮,把越暗的地方搞的越暗。
adjusted = gamma_trans(v_img, 9.3)

3.由于有些属于线上的点可能会比较暗淡,因此想了个法子,把所有像素乘以一个比较大的数字,在加上一定的数值。这样的话,线上比较暗淡的点也会变亮。
adjusted = cv2.convertScaleAbs(adjusted, alpha=13, beta=20)

4.此时线上的点已经大部分比较接近于白色了,这个时候阈值化一波。
_, adjusted = cv2.threshold(adjusted, 200, 255, cv2.THRESH_BINARY)

5.线段中间有空隙,需要把它们补上白色才好计算轮廓,所以撸一发膨胀。这里为了尽可能的把孔隙补上,所以核搞得比较大。
kernel = np.ones([12, 12], dtype=np.uint8)
adjusted = cv2.dilate(adjusted, kernel, iterations=2)

6.反个相,因为轮廓检测默认检测得是白色区域,但我们需要的是黑色区域的轮廓。
adjusted = np.ones([adjusted.shape[0], adjusted.shape[1]], dtype=np.uint8) * 255 - adjusted

7.轮廓检测,从众多轮廓中挑选出最大的轮廓。

8.计算最大轮廓的一阶矩就能算出轮廓的中心点坐标。
M = cv2.moments(contours[max_contour_index])
center_x = int(M["m10"] / M["m00"])
center_y = int(M["m01"] / M["m00"])
大概测试了20几次,对了19次。估计这个验证码的图库本身就不大,所以这么做就够用了。

如果想泛化能力更强的话,还是建议多采集一些图并且用一些网图生成一些类似的图,然后训练出一个分割模型来做分割。毕竟如果验证码的图变骚了,那么这种纯图像处理的法子可能就不适用了。