这是一个可能的解决方案:首先,尝试获取文本的分割掩码。使用大的、漂亮的rectangular structuring element 应用积极的dilation 操作。我们的想法是获得大块文本,这样我们就可以清楚地看到它们之间的分隔线。接下来,reduce 将图像添加到 MAX (255) 列,其中每个值都是每个扩张图像行的最大像素值。如果您反转缩小的图像并找到contours,您将获得您正在寻找的文本块之间的空间。最后,获取空白的平均值或中间点,并在此垂直高度绘制line。
让我们看看代码:
# imports:
import cv2
import numpy as np
# Set image path
imagePath = "C://opencvImages//"
imageName = "PQZUL.jpg"
# Read image:
inputImage = cv2.imread(imagePath + imageName)
# Store a copy for results:
inputCopy = inputImage.copy()
# Convert BGR to grayscale:
grayInput = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Threshold via Otsu
_, binaryImage = cv2.threshold(grayInput, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Set kernel (structuring element) size:
kernelSize = (9, 9)
# Set operation iterations:
opIterations = 2
# Get the structuring element:
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernelSize)
# Perform Dilate:
dilateImage = cv2.morphologyEx(binaryImage, cv2.MORPH_DILATE, morphKernel,
None, None, opIterations, cv2.BORDER_REFLECT101)
这组操作为您提供了一个很好的分割掩码,如下所示:
现在,将此图像缩小为 MAX 列。这是图像的垂直缩小:
# Reduce matrix to a n row x 1 columns matrix:
reducedImage = cv2.reduce(dilateImage, 1, cv2.REDUCE_MAX)
# Invert the reduced image:
reducedImage = 255 - reducedImage
这是结果 - 在这里很难看到,但图像已缩减为仅一列,其中每个值都是为该特定图像行找到的最大像素强度值:
每个白色部分是每个文本块到新段落的“跳转” - 这些是我们正在寻找的 blob(或 contours)。让我们找到它们并计算它们的bounding boxes:
# Find the big contours/blobs on the filtered image:
contours, hierarchy = cv2.findContours(mask, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
# Store the poly approximation and bound
contoursPoly = [None] * len(contours)
separatingLines = [ ]
# We need some dimensions of the original image:
imageHeight = inputCopy.shape[0]
imageWidth = inputCopy.shape[1]
# Look for the outer bounding boxes:
for i, c in enumerate(contours):
# Approximate the contour to a polygon:
contoursPoly = cv2.approxPolyDP(c, 3, True)
# Convert the polygon to a bounding rectangle:
boundRect = cv2.boundingRect(contoursPoly)
# Get the bounding rect's data:
[x,y,w,h] = boundRect
到目前为止我们已经有了bounding boxes的坐标,我们需要想办法得到每个垂直坐标的中点。有几个解决方案,我决定只获取边界框的height 并计算它的中间坐标。在这里,仍然在 for 循环内:
# Calculate line middle (vertical) coordinate,
# Start point and end point:
lineCenter = y + (0.5 * h)
startPoint = (0,int(lineCenter))
endPoint = (int(imageWidth),int(lineCenter))
# Store start and end points in list:
separatingLines.append((startPoint, endPoint))
# Draw the line:
color = (0, 255, 0)
cv2.line(inputCopy, startPoint, endPoint, color, 2)
# Show the image:
cv2.imshow("inputCopy", inputCopy)
cv2.waitKey(0)
我已将起点和终点存储在separatingLines 列表中,因此您可以在需要时检索数据。结果如下: