【问题标题】:Detect image orientation angle based on text direction根据文本方向检测图像方向角度
【发布时间】:2019-09-19 12:06:04
【问题描述】:

我正在执行一项 OCR 任务,以从多个身份证明文件中提取信息。一个挑战是扫描图像的方向。需要固定 PAN、Aadhaar、驾驶执照或任何身份证明的扫描图像的方向。

已经在 Stackoverflow 和其他论坛上尝试过所有建议的方法,例如 OpenCV minAreaRect、霍夫线变换、FFT、单应性、带有 psm 0 的 tesseract osd。没有一个有效。

逻辑应返回文本方向的角度 - 0、90 和 270 度。附上0、90、270度的图片。这与确定偏度无关。

【问题讨论】:

  • 直接的方法是将光学字符识别应用于 4 个旋转的图像,并保留带有“印度”一词的图像,或者使用分段字符串的某种测试来获得最高分。为此,可以考虑使用 opencv、numpy、Image 和 pytesseract 库。你能发布一个显示你尝试过的最小代码吗?
  • @francis,感谢您的评论和建议。由于 cmets 的字符限制,为简洁起见,我将代码 sn-ps 作为 cmets 在下面单独发布,由于某种原因,代码显示为纯文本
  • 这是 pytesseract,目的是忽略抽象方向并让 tesseract 隐式处理,效果不太好:config = ('stdout --psm 0 --oem 0 -l osd -c min_characters_to_try=5') imgPath = sys.argv[1] img = cv2.imread(imgPath) text = pytesseract.image_to_osd(img, config=config) print(text)
  • 这是 HOG:im = cv2.imread(imgPath) im = np.float32(im) / 255.0 gx = cv2.Sobel(im, cv2.CV_32F, 1, 0, ksize=1 ) gy = cv2.Sobel(im, cv2.CV_32F, 0, 1, ksize=1) mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True) print(angle[0])
  • 使用霍夫线变换:img_edges = cv2.Canny(img_before, 100, 200, openingSize=3) lines = cv2.HoughLinesP(img_edges, 1, math.pi / 180.0, 100, minLineLength=100 , maxLineGap=5) 角度 = [] for x1, y1, x2, y2 in lines[0]: cv2.line(img_before, (x1, y1), (x2, y2), (255, 0, 0), 3 ) angle = math.degrees(math.atan2(y2 - y1, x2 - x1)) Angles.append(angle) median_angle = np.median(angles) #print(median_angle) print("角度为 {}".format(中值角度))

标签: python image opencv image-processing computer-vision


【解决方案1】:

这是一种基于大部分文本偏向一侧的假设的方法。这个想法是我们可以根据主要文本区域的位置来确定角度

  • 将图像转换为灰度和高斯模糊
  • 获取二值图像的自适应阈值
  • 使用轮廓区域查找轮廓和过滤
  • 在蒙版上绘制过滤轮廓
  • 根据方向水平或垂直分割图像
  • 计算每一半的像素数

转换为灰度和高斯模糊后,我们自适应阈值得到二值图像

从这里我们找到轮廓并使用轮廓区域进行过滤以去除小的噪声颗粒和大的边界。我们将通过此过滤器的任何轮廓绘制到蒙版上

为了确定角度,我们根据图像的尺寸将图像分成两半。如果width > height 那么它必须是水平图像,所以我们垂直分成两半。如果height > width,那么它必须是垂直图像,所以我们水平分成两半

现在我们有两半,我们可以使用cv2.countNonZero() 来确定每一半的白色像素数量。以下是确定角度的逻辑:

if horizontal
    if left >= right 
        degree -> 0
    else 
        degree -> 180
if vertical
    if top >= bottom
        degree -> 270
    else
        degree -> 90

离开9703

右 3975

因此图像是 0 度。这是其他方向的结果

离开 3975

右 9703

我们可以得出结论,图像翻转了 180 度

这是垂直图像的结果。注意因为它是一个垂直的图像,我们水平分割

前 3947 个

底部 9550

因此结果是90度

import cv2
import numpy as np

def detect_angle(image):
    mask = np.zeros(image.shape, dtype=np.uint8)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (3,3), 0)
    adaptive = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,15,4)

    cnts = cv2.findContours(adaptive, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    for c in cnts:
        area = cv2.contourArea(c)
        if area < 45000 and area > 20:
            cv2.drawContours(mask, [c], -1, (255,255,255), -1)

    mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
    h, w = mask.shape
    
    # Horizontal
    if w > h:
        left = mask[0:h, 0:0+w//2]
        right = mask[0:h, w//2:]
        left_pixels = cv2.countNonZero(left)
        right_pixels = cv2.countNonZero(right)
        return 0 if left_pixels >= right_pixels else 180
    # Vertical
    else:
        top = mask[0:h//2, 0:w]
        bottom = mask[h//2:, 0:w]
        top_pixels = cv2.countNonZero(top)
        bottom_pixels = cv2.countNonZero(bottom)
        return 90 if bottom_pixels >= top_pixels else 270

if __name__ == '__main__':
    image = cv2.imread('1.png')
    angle = detect_angle(image)
    print(angle)

【讨论】:

  • 感谢您的建议和代码。这是一个非常有趣的想法。将尝试和更新。正在处理多个 ID 文档,文本区域的存在会有所不同,可能需要检测文档的类型并稍微调整逻辑。
  • 我已经尝试了一些示例图像,并且该方法似乎有效。再次感谢您的想法
猜你喜欢
  • 1970-01-01
  • 2011-02-03
  • 1970-01-01
  • 2018-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-11
  • 1970-01-01
相关资源
最近更新 更多