You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现发票、表单类图像正确旋转/翻转的技术问题咨询

解决发票/表单图像旋转角度检测不准确的问题

看起来你的代码在角度检测环节存在几个关键问题,导致部分图像无法正确旋转。咱们一步步拆解问题并修复:

问题分析

  1. 霍夫线遍历错误:cv2.HoughLinesP返回的lines是形状为(N,1,4)的数组(N是检测到的线条数),你的代码里for x1, y1, x2, y2 in lines[0]会把单条线的四个坐标当成独立元素遍历,实际上只处理了一条线的部分数据,完全忽略了其他检测到的线条,这会导致角度样本过少,中位数计算偏差极大。
  2. 角度未归一化:原始计算的角度范围是-180到180度,但对于文档类图像,我们只需要关注-45到45度之间的有效旋转角度(超过这个范围的旋转,其实可以通过反向旋转更小的角度来实现,比如旋转-90度等价于旋转90度,但需要结合图像方向判断)。
  3. 未处理90度增量旋转的场景:发票/表单通常是90度、180度这类增量旋转的,直接使用原始中位数角度可能会得到非标准角度,导致旋转后仍不符合预期。

修正后的代码

import numpy as np
import cv2
import math
from scipy import ndimage

def correct_image_rotation(image_path):
    # 读取图像
    img_before = cv2.imread(image_path)
    # cv2.imshow("Before", img_before)
    # key = cv2.waitKey(0)

    # 灰度化+边缘检测
    img_gray = cv2.cvtColor(img_before, cv2.COLOR_BGR2GRAY)
    img_edges = cv2.Canny(img_gray, 50, 150, apertureSize=3)

    # 霍夫线检测:调整参数适配文档类图像
    lines = cv2.HoughLinesP(
        img_edges,
        rho=1,
        theta=math.pi / 180.0,
        threshold=80,
        minLineLength=80,
        maxLineGap=10
    )

    angles = []
    if lines is not None:
        # 正确遍历所有检测到的线条
        for line in lines:
            x1, y1, x2, y2 = line[0]
            # 计算线条角度
            angle = math.degrees(math.atan2(y2 - y1, x2 - x1))
            angles.append(angle)

        # 归一化角度到-45°~45°范围
        normalized_angles = []
        for angle in angles:
            if angle < -45:
                normalized_angles.append(angle + 90)
            elif angle > 45:
                normalized_angles.append(angle - 90)
            else:
                normalized_angles.append(angle)

        # 计算中位数角度
        median_angle = np.median(normalized_angles)

        # 进一步调整到最接近的90°倍数(适配文档旋转场景)
        # 因为文档通常是90°/180°/-90°旋转,这里做二次校准
        if abs(median_angle) > 30:
            median_angle = 90 if median_angle > 0 else -90
        else:
            # 小角度视为不需要旋转,或者校准到0
            median_angle = round(median_angle / 90) * 90

    else:
        # 如果没有检测到线条,默认不旋转
        median_angle = 0

    # 执行旋转:ndimage.rotate是逆时针旋转,这里确保旋转后图像正立
    img_rotated = ndimage.rotate(img_before, median_angle, reshape=True)
    print(f"Angle is {median_angle}")

    # 保存结果
    cv2.imwrite('rotated.jpg', img_rotated)
    # cv2.imshow("After", img_rotated)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()

# 调用函数处理图像
correct_image_rotation('rotate_me.png')

关键改进点说明

  • 正确遍历霍夫线:通过for line in lines + x1, y1, x2, y2 = line[0]的方式,收集所有检测到的线条角度,确保样本足够多,中位数计算更准确。
  • 角度归一化:将角度映射到-45°~45°,避免因线条方向不同导致的角度偏差,比如垂直向下的线条角度-90°会被转换为0°,更符合文档旋转的实际需求。
  • 二次角度校准:针对文档类图像的旋转特性,将中位数角度调整到最接近的90°倍数,确保无论是左侧倒置还是右侧倒置的图像,都能旋转到正确的正立方向。
  • 鲁棒性处理:增加了线条检测失败的 fallback 逻辑,避免因无线条检测导致的报错。

这样调整后,无论是左侧还是右侧倒置的-90°图像,都能正确旋转到你期望的正立状态。

内容的提问来源于stack exchange,提问作者Yashu Gupta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:22:44