You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Python中使用OpenCV无法正确裁剪身份证扫描件的问题求助

Python中使用OpenCV无法正确裁剪身份证扫描件的问题求助

大家好,我最近在处理身份证扫描件的裁剪任务,想把扫描图里的身份证单独裁出来,但扫描件下方有一大片空白区域,目前写的代码没能正确识别身份证的边界,裁剪结果不符合预期。

先给大家看下原始的扫描件:

原始扫描件:画面上方是身份证,下方延伸出大量空白区域的扫描图像

我先写了一个预处理图像的函数,用来增强图像特征,方便后续轮廓检测:

def preprocess_before_crop_2(scan_path, output_dir):
    # Read the image
    original_image = cv2.imread(scan_path)
    # Grayscale
    gray = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
    # Histogram Equalization on grayscale image
    equalized = cv2.equalizeHist(gray)
    # Initial Denoising
    denoised = cv2.fastNlMeansDenoising(equalized, None, h=20, templateWindowSize=7, searchWindowSize=21)
    # Sharpening kernel
    kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
    sharpened = cv2.filter2D(denoised, -1, kernel)
    # Bilateral filter
    bilateral_filtered = cv2.bilateralFilter(sharpened, d=9, sigmaColor=75, sigmaSpace=75)
    # Increase Contrast
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
    contrast = clahe.apply(bilateral_filtered)
    # Apply slight Gaussian blur before binarization for anti-aliasing
    blurred = cv2.GaussianBlur(contrast, (3, 3), 0)
    # Binary conversion with Otsu's thresholding
    _, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    # Adaptive thresholding
    adaptive_thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
    return adaptive_thresh

接着是裁剪用的函数,思路是通过轮廓检测找到最大的符合宽高比的 bounding box,然后裁剪:

def crop_document(scan_path, output_dir):
    original_image = cv2.imread(scan_path)
    # preprocess image
    preprocessed_image = preprocess_before_crop(scan_path, output_dir)

    contours, hierarchy = cv2.findContours(preprocessed_image,cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    
    # Find object with the biggest bounding box
    mx = (0,0,0,0)      # biggest bounding box so far
    mx_area = 0
    areas = []
    for cont in contours:
        x,y,w,h = cv2.boundingRect(cont)
        area = w*h
        ratio = float(w) / float(h)
        areas.append((area,ratio))
        if area > mx_area and ratio > 1:
            mx = x,y,w,h
            mx_area = area

    x,y,w,h = mx

    # Crop and save
    cropped_image=original_image[y:y+h,x:x+w]
    return cropped_image

但现在的问题是,裁剪出来的区域不对,我用红色框在结果图里标出了真正想要裁剪的范围——应该是完整的身份证,但目前代码裁出来的部分没覆盖全身份证,或者说没正确识别它的边界。

裁剪结果图:当前裁剪出的区域不符合预期,红色矩形标注了目标的身份证完整区域

我试过调整预处理步骤,比如去掉一些滤波步骤、更换阈值方法,但都没能解决问题,想请教下各位有没有什么改进的思路?

另外补充一下,这是我最初上传的原始扫描件,避免大家混淆:

原始扫描件(补充版):包含身份证和下方空白区域的完整扫描图

备注:内容来源于stack exchange,提问作者Selphiron

火山引擎 最新活动