如何使用Python OpenCV对文本图像进行去倾斜处理并检索其新的边界框?

4

我有一张收据图片,我使用matplotlib绘制了它,如果你看到这张图片,你会发现其中的文本并不是水平的。如何进行去斜和修复?

from skimage import io
import cv2

# x1, y1, x2, y2, x3, y3, x4, y4
bbox_coords = [[20, 68], [336, 68], [336, 100], [20, 100]]

image = io.imread('https://i.ibb.co/3WCsVBc/test.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

fig, ax = plt.subplots(figsize=(20, 20))
ax.imshow(gray, cmap='Greys_r')

# for plotting bounding box uncomment the two lines below
#rect = Polygon(bbox_coords, fill=False, linewidth=1, edgecolor='r')
#ax.add_patch(rect)
plt.show()

print(gray.shape)
(847, 486)

收据图片

我认为如果我们想要去除偏斜,首先需要找到边缘,因此我尝试使用Canny算法找到边缘,然后获取如下的轮廓。

from skimage import filters, feature, measure

def edge_detector(image):
    image = filters.gaussian(image, 2, mode='reflect')
    edges = feature.canny(image)
    contours = measure.find_contours(edges, 0.8)
    return edges, contours

fig, ax = plt.subplots(figsize=(20, 20))

ax.imshow(gray, cmap='Greys_r'); 
gray_image, contours = edge_detector(gray)

for n, contour in enumerate(contours):
    ax.plot(contour[:, 1], contour[:, 0], linewidth=2)

从上面的代码中得到的边缘是每个文本的边缘,但这不是我需要的。我需要得到收据的边缘,对吗?
另外,我需要一种方法来获取去斜图像后的新边界框坐标(即将图像变直)?
如果有人已经解决了类似的问题,请帮帮我?谢谢。

https://dev59.com/YVsW5IYBdhLWcg3wbm0O#35014061 - Miki
@user_12 您已更改问题标题。那么,显示的“绿色”框不具有坐标吗? - stovfl
@stovfl,我已经更改了问题标题,因为它显示我的问题是一个重复的问题,但在我的问题正文中,我问如何获取去倾斜边界框坐标,并且我没有改变正文中的任何内容。 - user_12
@user_12:“当我去倾斜……旧的边界框不起作用了。”:那么,按照您之前所说,更新边界框有什么问题吗? - stovfl
@user_12 你是否在寻找类似这样的东西:robustly-crop-rotated-bounding-box-on-photosextracting-selected-text-by-bounding-box-from-an-image - stovfl
显示剩余5条评论
1个回答

9
这是一个修改后的Projection Profile方法的实现,用于校正倾斜图像,如基于投影谱的JBIG压缩图像倾斜估计算法所述。获得二值图像后,想法是以各种角度旋转图像并在每次迭代中生成像素直方图。为了确定倾斜角度,我们比较峰值之间的最大差异,并使用这个倾斜角度旋转图像以校正倾斜。可以通过delta值调整要确定的峰值数量,delta值越低,将检查更多的峰值,但代价是处理时间更长。

变化前->变化后

倾斜角度:-2

代码

import cv2
import numpy as np
from scipy.ndimage import interpolation as inter

def correct_skew(image, delta=1, limit=5):
    def determine_score(arr, angle):
        data = inter.rotate(arr, angle, reshape=False, order=0)
        histogram = np.sum(data, axis=1, dtype=float)
        score = np.sum((histogram[1:] - histogram[:-1]) ** 2, dtype=float)
        return histogram, score

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] 

    scores = []
    angles = np.arange(-limit, limit + delta, delta)
    for angle in angles:
        histogram, score = determine_score(thresh, angle)
        scores.append(score)

    best_angle = angles[scores.index(max(scores))]

    (h, w) = image.shape[:2]
    center = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D(center, best_angle, 1.0)
    corrected = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, \
            borderMode=cv2.BORDER_REPLICATE)

    return best_angle, corrected

if __name__ == '__main__':
    image = cv2.imread('1.jpg')
    angle, corrected = correct_skew(image)
    print('Skew angle:', angle)
    cv2.imshow('corrected', corrected)
    cv2.waitKey()

注意: 根据图像需要,您可能需要调整deltalimit值。 delta值控制迭代步骤,它会迭代直到控制最大角度的limit。 这种方法通过迭代检查每个角度+ delta来实现,目前仅能在+/- 5度范围内纠正偏斜。 如果您需要更大角度的校正,请调整limit值。 对于处理倾斜的另一种方法,请查看旋转倾斜图像以使其直立的替代方法


非常感谢 :) ...我在我的问题中还有一个要求,对于原始图像,我还有标题“YONG TAT HARDWARE TRADING”的边界框坐标,它的形式为[x1,y1,x2,y2,x3,y3,x4,y4](即矩形的四个顶点),当我们纠正倾斜并旋转图像时,如何修改我的边界框坐标以支持新的裁剪图像?这是我的主要问题。 - user_12
你能解释一下在旋转图像上找到新边界框的意思吗?你是指我们需要重新注释图像吗? - user_12
我只是好奇,我想知道我正在寻找的是否可能实现?如果可能的话,我应该再问一个问题,这样其他人就可以回答了。 - user_12
1
是的,我会再次注释图像来完成这个任务。我认为使用一些旋转矩阵可能可以实现你想要的效果,但你应该另外提一个问题来解决这个任务。 - nathancy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接