Python中如何去除验证码的干扰线并进行图像矫正?

最近在用 Python 做爬虫,碰到了这种验证码(降噪 /二值化处理后的)

现在想要将干扰线去掉,最好能矫正一下字符,不吝赐教。


Python中如何去除验证码的干扰线并进行图像矫正?
9 回复

话说我的图片呢


import cv2
import numpy as np
from skimage import morphology

def remove_interference_lines(image_path):
    """
    去除验证码干扰线的主要步骤
    """
    # 1. 读取图像并转为灰度
    img = cv2.imread(image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 2. 二值化处理
    _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    
    # 3. 使用形态学操作去除细线(干扰线通常比字符细)
    # 先腐蚀去除细线
    kernel_erode = np.ones((2, 2), np.uint8)
    eroded = cv2.erode(binary, kernel_erode, iterations=1)
    
    # 再膨胀恢复字符
    kernel_dilate = np.ones((3, 3), np.uint8)
    cleaned = cv2.dilate(eroded, kernel_dilate, iterations=1)
    
    # 4. 可选:使用连通组件分析去除小面积噪声
    num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(cleaned, connectivity=8)
    
    # 创建掩码,只保留面积较大的组件(假设字符面积较大)
    min_area = 50  # 根据实际情况调整
    mask = np.zeros_like(cleaned)
    for i in range(1, num_labels):
        if stats[i, cv2.CC_STAT_AREA] > min_area:
            mask[labels == i] = 255
    
    return mask

def correct_image_skew(image):
    """
    图像倾斜矫正
    """
    # 1. 边缘检测
    edges = cv2.Canny(image, 50, 150, apertureSize=3)
    
    # 2. 霍夫变换检测直线
    lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
    
    if lines is not None:
        # 3. 计算平均角度
        angles = []
        for line in lines:
            rho, theta = line[0]
            angle = theta * 180 / np.pi - 90
            if abs(angle) < 45:  # 只考虑接近水平的线
                angles.append(angle)
        
        if angles:
            # 4. 计算平均倾斜角度
            median_angle = np.median(angles)
            
            # 5. 旋转矫正
            (h, w) = image.shape[:2]
            center = (w // 2, h // 2)
            M = cv2.getRotationMatrix2D(center, median_angle, 1.0)
            corrected = cv2.warpAffine(image, M, (w, h), 
                                      flags=cv2.INTER_CUBIC, 
                                      borderMode=cv2.BORDER_REPLICATE)
            return corrected
    
    return image  # 如果没有检测到明显倾斜,返回原图

def process_captcha(image_path, output_path=None):
    """
    完整的验证码处理流程
    """
    # 步骤1: 去除干扰线
    cleaned = remove_interference_lines(image_path)
    
    # 步骤2: 倾斜矫正
    corrected = correct_image_skew(cleaned)
    
    # 步骤3: 最终二值化处理
    _, final = cv2.threshold(corrected, 127, 255, cv2.THRESH_BINARY)
    
    if output_path:
        cv2.imwrite(output_path, final)
    
    return final

# 使用示例
if __name__ == "__main__":
    # 处理验证码图片
    result = process_captcha('captcha.jpg', 'processed_captcha.jpg')
    
    # 显示结果对比
    original = cv2.imread('captcha.jpg')
    cv2.imshow('Original', original)
    cv2.imshow('Processed', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

核心思路:

  1. 去干扰线:利用干扰线通常比字符细的特点,通过形态学操作(腐蚀+膨胀)过滤细线
  2. 倾斜矫正:用霍夫变换检测文本基线,计算倾斜角度后旋转矫正

参数调整建议:

  • 形态学操作的核大小需要根据验证码具体样式调整
  • 连通组件的最小面积阈值根据字符大小设置
  • 霍夫变换的参数需要根据图像分辨率调整

一句话总结:用形态学去噪+霍夫变换矫正,具体参数得看你的验证码长啥样。

怎么发本地图片😓

1, 大佬们发图似乎都用 https://sm.ms

2, 看不到图,但是我瞎说一下:open cv ,先灰度化, 再用 sobel 算一下 xy 方向上的梯度,之后相减,最后 blur 一下,行不行?

厉害了,不过算法那些搞不懂~

可以直接上 CNN+RNN 进行端到端验证码识别,GitHub 上有相关代码

pytesser

试过了 效果很差

回到顶部