Do automation/test card sliding notches? Try this 2023 optimized OpenCV solution

Students who have been tossing about automated testing and crawler authorization verification recently should not be able to avoid the sliding verification code - Jiexian, NetEase Yidun, and hCaptcha are all using it. Although the deep learning solution is powerful, the threshold for standardizing data and setting up a GPU environment is too high; Pure OpenCV requires no training, is quick to get started, and can run on a single CPU. With further optimization of parameters and processes in 2023, it will be more than enough to deal with more than 80% of conventional gaps!

This article will help you:

  • Sorting out the core features of modern sliding notches
  • Use the latest OpenCV 4.7 API to implement a set of robust recognizers
  • Attached are practical performance/robustness optimization tips

⚠️ Important note: This article is only used for authorized technical research and legal automated testing. For actual application, please abide by the website's "Terms of Service" and robots.txt, and control the frequency of requests!


1. First understand what the sliding gap looks like (key!)

Many students use template matching and Canny as soon as they come up, and the results are very poor - the core reason is that the general screening rules for regular gaps are not grasped. The characteristics of mainstream gaps in 2023 (such as the third generation lightweight version of Jiexian) are actually very fixed:

Universal gap feature (adapted to mainstream products such as JiExperience/Yidun)

  1. Shape: A simplified version of the "concave" cut out of a square/rectangular shape (usually a regular polygon with clear outlines)
  2. Position: 50%-90% of the area** on the right side of the picture** (the system is afraid that dragging too far to the left will be too easy)
  3. Size: The width is 10%-30% of the original image, and the height is close to the width (avoid interference objects that are too flat or too sharp)
  4. Filling Degree: The actual pixel area within the outline, accounting for 60%-90% of the outer rectangle (excluding hollow/solid interference from text and watermarks)

2. Environment preparation: 30 seconds to set up the foundation

2.1 Dependent installation (fixed version to avoid compatibility issues)

# 推荐用Python 3.8-3.10,OpenCV 4.7优化了内存和部分算法
pip install opencv-python==4.7.0.72 numpy==1.24.2

2.2 Test images (don’t just use one!)

Find at least 10 pictures of different scenes and different notch styles:

  • Cut from the official website/public demo of the third generation of JiExperience
  • Cut from NetEase Yidun lightweight version
  • Climbed it by myself (within legal limits!)

3. Core identification process: four steps for the 2023 optimized version

Many old tutorials used "Grayscale → Canny → Contour Screening". Now we have added CLAHE Histogram Equalization (processing darker/brighter verification codes), Morphological Closure Operation (filling small gaps in the gap outline), and the process is more stable:

Complete runnable code

import cv2
import numpy as np
from typing import Optional, Tuple

class SlideCaptchaSolver:
    def __init__(self, debug: bool = False):
        self.debug = debug

    def solve(self, image_path: str) -> Optional[int]:
        """
        识别滑动验证码缺口的起始X坐标
        :param image_path: 验证码原图路径(必须是有缺口的完整图,不是缺口+背景分离的)
        :return: 缺口起始X坐标(像素),识别失败返回None
        """
        # 1. 读取图像并校验
        image = cv2.imread(image_path)
        if image is None:
            raise ValueError(f"无法加载图像:{image_path}")
        img_h, img_w = image.shape[:2]

        # 2. 2023优化版预处理:偏暗/偏亮自适应增强+高斯模糊降噪
        processed = self._preprocess(image)

        # 3. 边缘检测+形态学闭运算填充轮廓缝隙
        edges = self._edge_detection(processed)

        # 4. 查找轮廓+按2023主流规则筛选
        contours, _ = cv2.findContours(edges, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
        targets = self._filter_contours(contours, img_w, img_h)

        if not targets:
            print("未找到符合条件的缺口!")
            return None

        # 取外接矩形面积最大的那个(最可能是缺口)
        target = sorted(targets, key=lambda x: x[2] * x[3], reverse=True)[0]
        x, _, w, _ = target

        if self.debug:
            self._debug_show(image, edges, target)

        return x + w // 2  # 通常返回缺口中心点X坐标,更贴合拖动需求

    def _preprocess(self, image: np.ndarray) -> np.ndarray:
        """预处理:自适应亮度增强+高斯模糊"""
        # 转LAB颜色空间(L通道是亮度,A/B是颜色,处理亮度不会影响颜色)
        lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
        l, a, b = cv2.split(lab)

        # 2023推荐参数:clipLimit=3.0(对比度别太高,避免产生噪点)
        clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
        l_enhanced = clahe.apply(l)

        # 合并LAB通道+转回BGR
        merged = cv2.merge([l_enhanced, a, b])
        bgr_enhanced = cv2.cvtColor(merged, cv2.COLOR_LAB2BGR)

        # 高斯模糊:(5,5)核,刚好过滤高频噪点又保留边缘
        return cv2.GaussianBlur(bgr_enhanced, (5, 5), 0)

    def _edge_detection(self, image: np.ndarray) -> np.ndarray:
        """边缘检测+形态学闭运算填充缝隙"""
        # Canny参数:100低阈值,200高阈值(常规缺口通用)
        edges = cv2.Canny(image, 100, 200)

        # 形态学闭运算:(5,5)矩形核,填充缺口轮廓的小断裂
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
        return cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)

    def _filter_contours(
        self, contours: list, img_w: int, img_h: int
    ) -> list[Tuple[int, int, int, int]]:
        """按2023主流缺口规则筛选轮廓"""
        targets = []
        right_area_start = img_w * 0.5  # 只看右侧50%的区域

        for cnt in contours:
            # 计算外接矩形
            x, y, w, h = cv2.boundingRect(cnt)
            # 过滤左侧区域
            if x < right_area_start:
                continue
            # 过滤宽高比太奇怪的
            aspect_ratio = w / h
            if not (0.8 < aspect_ratio < 1.2):  # 现在主流缺口更接近正方形
                continue
            # 过滤尺寸太小/太大的
            if not (0.1 * img_w < w < 0.3 * img_w):
                continue
            # 过滤填充度太低/太高的(排除文字、实心块)
            area = cv2.contourArea(cnt)
            rect_area = w * h
            extent = area / rect_area
            if not (0.6 < extent < 0.9):
                continue

            targets.append((x, y, w, h))

        return targets

    def _debug_show(self, image: np.ndarray, edges: np.ndarray, target: Tuple[int, int, int, int]) -> None:
        """调试模式:展示原图、边缘图、带框目标图"""
        x, y, w, h = target
        # 在原图上画矩形+中心点
        cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.circle(image, (x + w // 2, y + h // 2), 5, (0, 0, 255), -1)
        # 展示
        cv2.imshow("Debug-Original", image)
        cv2.imshow("Debug-Edges", edges)
        cv2.waitKey(0)
        cv2.destroyAllWindows()


if __name__ == "__main__":
    # 测试
    solver = SlideCaptchaSolver(debug=True)
    result = solver.solve("test_captcha.png")
    print(f"缺口中心点X坐标:{result}")

4. What other tips can further improve the recognition rate?

4.1 Performance optimization (single CPU can also be 2-3 times faster)

💡 Image scaling: If the original image is about 300x150, no need to reduce it; if it exceeds 600x300, scale it down to 300x150, the recognition accuracy will be almost unchanged, and the speed will be much faster.

# 在solve函数开头加
scale = 0.5  # 根据原图尺寸调整
if max(img_w, img_h) > 600:
    image = cv2.resize(image, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)
    img_w, img_h = img_w * scale, img_h * scale  # 筛选参数也要同步缩放

4.2 Enhanced robustness (deal with more than 85% of interference)

🚀 Multi-threshold Canny: If a single Canny parameter does not work, you can try(100, 200)(80, 180)(120, 220)Three parameters, take the intersection contour, which can filter out many noise edges.

🚀 Color Space Supplement: If the LAB processing effect is not good, you can convert to HSV - H channel can separate the color of the background and the gap. For example, the tone of some gaps in Jiexuan is reddish, and the H channel threshold can be used to extract the foreground more cleanly.


Extended resources

This article is only used for authorized technical research and legal automated testing (such as your own company's system, testing allowed by open APIs)! If you crack the commercial verification code without authorization, you may violate the "Network Security Law" and "Criminal Law" (such as the crime of illegal intrusion into computer information systems and the crime of damaging computer information systems), and you will be responsible for the consequences!

The confrontation with verification code technology is ongoing - if you need to identify complex dynamic blur and 3D rotation verification codes, it is still recommended to use the official API or find a professional AI team to cooperate!