Python对旋转图片验证码的识别和破解(二)

Python对旋转图片验证码的识别和破解

本文主要使用python + selenium来破解旋转突破的验证码;其中用到numpy和OpenCV(CV2)来进行图片拼接,转换,遮罩,识别等

(二)将验证码图片与所有的图片拼接的大图比较,找到旋转角度

  • 使用cv2.getRotationMatrix2D设置选择矩阵,warpAffine进行图片旋转

getRotationMatrix2D比较简单,参数为:旋转圆心坐标(x,y), 旋转角度, 放缩比例

  • 使用cv2.matchTemplate来匹配图片

matchTemplate使用各种不同的方法来匹配图片,具体可以参考资料:
result = cv2.matchTemplate( img_all, img, cv2.TM_CCOEFF_NORMED)
min_max_loc = cv2.minMaxLoc(result)

其中matchTemplate的最后一个参数为匹配方法,具体说明见:https://docs.opencv.org/3.3.0/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d
min_max_loc返回(匹配度和匹配位置),但是匹配度与使用的最后一个参数相关,有的匹配方法,匹配度越大越好,有的相反。在此我们使用了TM_CCOEFF_NORMED,并取min_max_loc中的maxVal,越大(接近1)越相似。

核心代码如下:

def is_existed(img_all, img, semilar=0.9):
    '''
    在img_all中寻找img,当相似度到达semilar时停止
    参数:
        img_all:
        img:
        semilar:相似度阀值
    返回:    (maxValue, maxLoc, Angle)
        maxValue: 相似度- 0:不相识,1:全相似
        maxLoc:最相似的位置(x,y)
        Angle:转换到最相似的旋转角度
    '''
    if semilar <0 or semilar >1:
        semilar = 0.9

    max_val = 0  # 相似度
    # 取决于matchTemplate的最后一个参数,对于多数方法,越大越好;对于有2个方法,越小越好)
    angle = 0  # 旋转角度
    max_loc = (0,0)
    h, w = img.shape[:2]

    for i in range(0, 360, 1):
        matRotate = cv2.getRotationMatrix2D((h*0.5, w*0.5), i, 1)
        dst = cv2.warpAffine(img, matRotate, (h, w))
        # if i%30==0:
        #     show(dst)
        result = cv2.matchTemplate(
            img_all, dst, cv2.TM_CCOEFF_NORMED)
        min_max_loc = cv2.minMaxLoc(result)  # 匹配程度最大的左上角位置 (x,y)
        if min_max_loc[1] > max_val:
            max_val = min_max_loc[1]
            max_loc =min_max_loc[3]
            angle = i
            # print(f'匹配度 = {max_val}, 旋转角度 = {i}')
            if max_val >= semilar:  # 很高的匹配度,认为已经ok了
                break
    return (max_val, max_loc, angle)

可以改进的地方(1):

上述代码比较粗糙,直接360度按步长为1度旋转,比较好的方法从粗到细,分段比较,速度快得多

比如先按步长10,分为0,10,20,…350度,比较最匹配的角度,然后以最匹配的角度的前后10度,以1度的步长搜索,这样两步共56次匹配就完成了(第一次匹配执行36次,第二次匹配执行20次),而原来需要执行360次匹配,新方法速度快了6倍。

如果需要更精细的匹配,比如精细到0.1度,那么原来需要执行3600次(360/0.1=3600),现在只要执行36+20+20=76次,新方法执行速度比原来快50倍

step = 10
start = 0
stop = 360
while True:
    if step< 1:
        break
    max_val =0
    while start < stop:
        do_something() # 旋转start度, 并匹配,然后与max_val比较,如果更匹配,保存新的匹配度,匹配位置max_loc,旋转角度angle
        start +=step
    start = angle - step + step*0.1
    stop = angle + step 
    step = step *0.1

可以改进的地方(2):

上述代码没有判断图片大小,当图片很大的时候,每次的匹配速度很慢,此时应该金字塔下采样cv2.pyrDown对img和image_all进行同步缩小,然后再进行matchTemplate,这样速度会快的多。

对图像缩放有resize和金字塔下采样两种,通常使用金字塔下采样。每执行一次下采样时,宽,高各缩放为原图的一半(每执行一次上采样,宽高放大为原来2倍)

模拟代码如下:

# 希望将验证码缩小为150像素以下
h, w = img.shape[:2]
levels = 0
while h>150:
    levels +=1
    img = cv2.pyrDown(img)
    h, w = img.shape[:2]

# 缩放img得到锁小次数,然后对img_all进行相同操作
for _ in range(levels):
    img_all = cv2.pyrDown(img_all)

你可能感兴趣的:(python,opencv)