在Python中使用opencv校正图像

问题描述 投票:0回答:1

我正在预处理 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
python opencv image-processing
1个回答
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
应用旋转矩阵。

这里还有一个关于其工作原理的小图:

© www.soinside.com 2019 - 2024. All rights reserved.