【问题标题】:Detect and crop a box in .pdf or image as individual images检测 .pdf 或图像中的框并将其裁剪为单个图像
【发布时间】:2019-07-17 04:30:02
【问题描述】:

我有一个包含手写内容的多页 .pdf(扫描图像),我想裁剪并存储为新的单独图像。例如,在下面的视觉效果中,我想将 2 个框内的笔迹提取为单独的图像。如何使用 python 自动为大型多页 .pdf 执行此操作?

我尝试使用 PyPDF2 包根据 (x,y) 坐标裁剪其中一个手写框,但是这种方法对我不起作用,因为手写框的边界/坐标并不总是相同对于pdf中的每一页。我相信检测盒子将是自动裁剪的更好方法。不确定它是否有用,但下面是我用于 (x,y) 坐标方法的代码:

from PyPDF2 import PdfFileReader, PdfFileWriter

reader = PdfFileReader('data/samples.pdf', 'r')

# getting the first page
page = reader.getPage(0) 

writer = PdfFileWriter()

# Loop through all pages in pdf object to crop based on (x,y) coordinates
for i in range(reader.getNumPages()):
    page = reader.getPage(i)
    page.cropBox.setLowerLeft((42,115)) 
    page.cropBox.setUpperRight((500, 245)) 
    writer.addPage(page)

outstream = open('samples_cropped.pdf','wb')
writer.write(outstream)
outstream.close()

提前感谢您的帮助

【问题讨论】:

  • PDF 是一种矢量格式。它没有以像素为单位的大小,直到通过在读取时提供密度来进行光栅化。因此,您需要先对其进行光栅化,或者如果它具有嵌入的图像,然后使用 pdfimages 之类的东西提取它。完成后,您可以使用 OpenCV 或 Imagemagick 查找轮廓或斑点,然后使用连接组件查找矩形的边界框。然后你可以裁剪这些区域。
  • @fmw42 感谢分享。我不是这方面的专家,所以请原谅我的新手问题。所以第1步只是将pdf中的所有页面转换为图像格式,比如jpeg?补充一下这个 pdf 文档是从扫描仪进纸器生成的可能会有所帮助,所以我不确定“嵌入式图像[s]”
  • 如果它被扫描,那么它很可能是嵌入在矢量 PDF 外壳中的光栅图像。所以最好的方法是使用 pdfimages 来提取光栅图像,最好是 PNG 或 TIFF 而不是 JPG。 JPG 是一种有损压缩格式。见linux.die.net/man/1/pdfimagescyberciti.biz/faq/easily-extract-images-from-pdf-file
  • @fmw42 我正在尝试按照您分享的 pdfimages linux 说明进行操作:cyberciti.biz/faq/easily-extract-images-from-pdf-file。我研究了一下,了解到我需要使用 subprocess 包在我的 python 代码中执行 linux 命令。但是如何正确安装 apt-get install poppler-utils ?我需要使用自制软件吗?如果相关,我在 macOS 上,使用 conda 虚拟环境,在 jupyter lab 上用 python 编码。
  • 最好检查 Homebrew 的那个包。我在 Mac 上,是从 MacPorts 完成的。

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


【解决方案1】:

这是一个使用 OpenCV 的简单方法

  • 将图像转换为灰度和高斯模糊
  • 阈值图像
  • 寻找轮廓
  • 遍历轮廓并使用轮廓区域进行过滤
  • 提取投资回报率

提取 ROI 后,您可以将每个图像保存为单独的图像,然后使用 pytesseract 或其他工具执行 OCR 文本提取。


结果

你提到了这个

手写框的边界/坐标对于 pdf 中的每一页并不总是相同的。

目前,您使用(x,y) 坐标的方法不是很可靠,因为这些框可能位于图像上的任何位置。更好的方法是使用最小阈值轮廓区域进行过滤以检测框。根据您想要检测的盒子的大小,您可以调整变量。如果您想要额外的过滤来防止误报,您可以添加到aspect ratio 作为另一种过滤机制。例如,计算每个轮廓的纵横比,然后如果它在界限内(比如对于正方形/矩形 ROI 的 0.81.2),那么它是一个有效的框。

import cv2

image = cv2.imread('1.jpg')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
thresh = cv2.threshold(blurred, 230,255,cv2.THRESH_BINARY_INV)[1]

# Find contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

# Iterate thorugh contours and filter for ROI
image_number = 0
min_area = 10000
for c in cnts:
    area = cv2.contourArea(c)
    if area > min_area:
        x,y,w,h = cv2.boundingRect(c)
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        ROI = original[y:y+h, x:x+w]
        cv2.imwrite("ROI_{}.png".format(image_number), ROI)
        image_number += 1

cv2.imshow('image', image)
cv2.waitKey(0)

【讨论】:

  • 感谢分享。我有几个初步问题 1.) 你会建议我如何将我的多页 pdf 转换/提取为图像?这是将图像转换为灰度和高斯模糊之前的第一步。 2.)您的解决方案是处理一张图像,如何修改它以一次处理多张图像,从而处理 pdf 文件中的所有页面?
  • @Steve 如果您的 PDF 是 PDF 矢量外壳中的光栅文件,那么您可以使用 pdfimages 提取光栅文件。在 Python 中,您需要使用子进程调用,因为 pdfimages 不是基于 Python 的。或者,您可以使用 Imagemagick 或其他基于 Python 的工具将您的 pdf 光栅化为多个图像。关于处理多个文件,您可以简单地从 nathancy 获取代码,并在从 PDF 中提取或转换的每个光栅文件上添加一个循环。
  • 1.) 这由您决定,您可以使用一些外部 Python 库来执行此操作。我个人会使用像smallpdf 这样的.pdf 到图像转换器。 2.) 将 .pdf 转换为 .png 图像后,您将拥有每个页面的图像。所有这些都在一个目录中。然后,您可以遍历每个图像并应用此解决方案
  • @nathancy 一旦我完成 pdf 到图像的转换并回复您,我将测试这种方法。再次感谢您分享此信息。很有帮助。
  • @devansvd 只是一个任意阈值。实际上,让 OpenCV 使用 Otsu 或自适应阈值自动确定值可能会更好
【解决方案2】:

使用定义的边界框作为单个图像检测和 pdf 或图像

对于小型项目而言,使用 Opencv 方法检测图像和裁剪是不合理的

from PIL import Image
def ImageCrop():
    img = Image.open("page_1.jpg")
    left = 90
    top = 580
    right = 1600
    bottom = 2000
    img_res = img.crop((left, top, right, bottom))
    with open(outfile4, 'w') as f:
        img_res.save(outfile4,'JPEG')
ImageCrop()

【讨论】:

    猜你喜欢
    • 2017-07-30
    • 2021-05-27
    • 2018-01-27
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多