我正在预处理 PDF 图像,最终将从其中提取文本。我使用
opencv
进行大部分预处理工作,由于客户端环境的限制,我只能坚持使用 opencv
进行图像处理。我有一个功能(如下)来校正图像,使其处于正确的方向,并且可以进一步提取文本(使用pytesseract
)。在运行该函数之前,我将 PDF 转换为图像并将其调整为预定大小(与原始大小大致相同)。这两个功能都工作得很好,并且似乎不是我下面的问题的罪魁祸首。
在所有这些图像中,有大约一个。 50-50 分为两种,一种是完全定向的图像,图像中的文本漂亮且笔直,另一些图像稍微煮熟,足以明显偏离,并且在尝试提取文本时也会导致问题。因此,需要一个抗时滞功能。我回顾了这篇文章并利用文章中的代码创建了以下内容:
# Code courtesy of Leo Ertuna for Becoming Human: Artificial Intelligence Magazine
## https://becominghuman.ai/how-to-automatically-deskew-straighten-a-text-image-using-opencv-a0c30aed83df
# Calculate skew angle of an image
def getSkewAngle(cvImage) -> float:
# Prep image, copy, convert to gray scale, blur, and threshold
newImage = cvImage.copy()
gray = cv2.cvtColor(newImage, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (9, 9), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Apply dilate to merge text into meaningful lines/paragraphs.
# Use larger kernel on X axis to merge characters into single line, cancelling out any spaces.
# But use smaller kernel on Y axis to separate between different blocks of text
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 5))
dilate = cv2.dilate(thresh, kernel, iterations=5)
# Find all contours
contours, hierarchy = cv2.findContours(dilate, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key = cv2.contourArea, reverse = True)
# Find largest contour and surround in min area box
largestContour = contours[0]
minAreaRect = cv2.minAreaRect(largestContour)
# Determine the angle. Convert it to the value that was originally used to obtain skewed image
angle = minAreaRect[-1]
if angle < -45:
angle = 90 + angle
return -1.0 * angle
def rotateImage(cvImage, angle: float):
newImage = cvImage.copy()
(h, w) = newImage.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
newImage = cv2.warpAffine(newImage, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
return newImage
# Deskew image
def deskew(cvImage):
angle = getSkewAngle(cvImage)
if abs(angle) < 0.90:
return rotateImage(cvImage, -1.0 * angle)
else:
return cvImage
我插入了两张图像,一张大部分处于正确的角度,另一张则非常明显倾斜。
print(getSkewAngle(working_pdf))
working_pdf_ds = deskew(working_pdf)
getSkewAngle(working_pdf_ds)
上述完美定向图像的输出是
-0.061542168259620667
-90.0
弯曲图像的输出是
-89.61195373535156
-90.0
基于这个新角度,我希望图像现在已经拉直并且看起来像完美定向的图像。然而,当我在去歪斜后查看图像本身时,明显歪斜的图像现在以 270 度角(顺时针)旋转。我尝试尝试在倾斜的图像上重新运行该函数以重新定位它,但是当它进行倾斜校正时,它会从图像的顶部和底部裁剪掉。
我不确定我到底在哪里出了问题,或者如何开始解决这个问题,所以非常感谢任何可以分享的建议。
我使用的实际 PDF/图像包含 PII,但我能够使用我获取代码的文章中的示例图像复制该问题,并遇到相同的问题。
原创
运行相差校正功能后
当打印此示例图像的原始角度,然后打印纠偏后的角度时,我得到以下输出:
-90.0
-0.0
该图像非常适合“经典”去歪斜。
import cv2
import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
im = cv2.imread("skewed.png") # read image
imGray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # turn to gray
imOTSU = cv2.threshold(imGray, 0, 1, cv2.THRESH_OTSU+cv2.THRESH_BINARY_INV)[1] # get threshold with positive pixels as text
coords = np.column_stack(np.where(imOTSU > 0)) # get coordinates of positive pixels (text)
angle = cv2.minAreaRect(coords)[-1] # get a minAreaRect angle
if angle < -45: # adjust angle
angle = -(90 + angle)
else:
angle = -angle
# get width and center for RotationMatrix2D
(h, w) = imGray.shape # get width and height of image
center = (w // 2, h // 2) # get the center of the image
M = cv2.getRotationMatrix2D(center, angle, 1.0) # define the matrix
rotated = cv2.warpAffine(im, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE) # apply it
将文本像素转为正类后,将其作为
column_stack
,然后使用 cv2.minAreaRect
。之后,只需调整角度并使用 cv2.warpAffine
应用旋转矩阵。
这里还有一个关于其工作原理的小图: