首页 > 解决方案 > 识别扫描的 PDF 图像中的页码

问题描述

我有很多 PDF,基本上是扫描的文档或书籍,所以每个 PDF 页面都有两个扫描的图像,我必须拆分这些页面并根据页面上写入的页数进行组织以进行打印。页面拆分不是问题(我使用的是 mutool 海报),问题是:“如何从页面(图像)的 PDF 部分检测页码?

这是一个页面示例

在此处输入图像描述

我尝试过使用 python + opencv + tesseract 但没有结果,因为我无法检测到数字的正确位置(它可以在任何角落),或者如果 opencv 检测到该位置,则 tesseract 无法检测到文本

标签: pythonopencvimage-processingocrtesseract

解决方案


这是一种方法

  • 将图像转换为灰度和反转图像
  • 扩张以获得字母作为单个轮廓
  • 寻找轮廓
  • 裁剪每个轮廓的 ROI 并投入 Pytesseract
  • 如果结果是数字,则保存 ROI

转换为灰度和反转图像

image = cv2.imread('2.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = 255 - gray

在此处输入图像描述

现在我们扩张以将字母/轮廓连接在一起。这个想法是页码轮廓将与页面上的其他字符分开,即使它可能位于任何角落

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(gray, kernel, iterations=4)

在此处输入图像描述

从这里我们找到轮廓,然后提取 ROI。我们将每个 ROI 投入到 Pytesseract 中。如果返回的结果都是数字,那么我们已经检测到页码 ROI,因此我们可以使用 Numpy 切片保存它

image_number = 0
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    ROI = original[y:y+h, x:x+w]
    data = pytesseract.image_to_string(ROI, lang='eng', config='--psm 10')
    if data.isdigit():
        print('Page #: ', data)
        cv2.imwrite("ROI_{}.png".format(image_number), ROI)
        image_number += 1

在此处输入图像描述

这是 Pytesseract 的结果和提取的 ROI

在此处输入图像描述

页码:110

完整代码

import cv2
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

image = cv2.imread('2.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = 255 - gray

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(gray, kernel, iterations=4)

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

image_number = 0
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    ROI = original[y:y+h, x:x+w]
    data = pytesseract.image_to_string(ROI, lang='eng', config='--psm 10')
    if data.isdigit():
        print('Page #: ', data)
        cv2.imwrite("ROI_{}.png".format(image_number), ROI)
        image_number += 1

cv2.imshow('gray', gray)
cv2.imshow('dilate', dilate)
cv2.imshow('original', original)
cv2.waitKey()

推荐阅读