如何找到文本字段的边线

How to find the side lines of the field of text

我有一个经过处理的图像,里面有文本,我想找到会触及文本字段边缘但不会穿过它并且会延伸到文本的整个侧面的线条的坐标。下图显示了我需要的(我画的红线显示了我想在原始图像上找到什么坐标的示例):

这不是那么简单,我不能只找到处理过的文本字段的边缘(左上角、右上角等),因为它可能是,f.e。段落的开头(这只是可能情况的一个示例):

文字的两边是一条直线,上下两边可能是弧形的,这样会更方便。

最好的方法是什么?

我能想到的任何方法要么不实用、低效,要么通常会给出错误的结果。

原始图像,以防有人需要处理:

思路是求所有文本的凸包。找到凸包后,我们找到它的边。如果边的 y 坐标变化大,x 坐标变化小(即线的斜率高),我们会认为它是边线。

结果图像:

代码:

import cv2
import numpy as np

def getConvexCoord(convexH, ind):
    yLines = []
    xLine = []
    for index in range(len(ind[0])):
        convexIndex = ind[0][index]

        # Get point
        if convexIndex == len(convexH) - 1:
            p0 = convexH[0]
            p1 = convexH[convexIndex]
        else:
            p0 = convexH[convexIndex]
            p1 = convexH[convexIndex + 1]

        # Add y corrdinate
        yLines.append(p0[0, 1])
        yLines.append(p1[0, 1])
        xLine.append(p0[0, 0])
        xLine.append(p1[0, 0])
    return yLines,xLine

def filterLine(line):
    sortX = sorted(line)
    # Find the median
    xMedian = np.median(sortX)
    while ((sortX[-1] - sortX[0]) > I.shape[0]):

        # Find out which is farther from the median and discard
        lastValueDistance = np.abs(xMedian - sortX[-1])
        firstValueDistance = np.abs(xMedian - sortX[0])
        if lastValueDistance > firstValueDistance:

            # Discard last
            del sortX[-1]
        else:
            # Discard first
            del sortX[0]

    # Now return mixX and maxX
    return max(sortX),min(sortX)


# Read image
Irgb = cv2.imread('text.jpg')
I = Irgb[:,:,0]

# Threshold
ret, Ithresh = cv2.threshold(I,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# Find the convex hull of the text
textPixels = np.nonzero(Ithresh)
textPixels = zip(textPixels[1],textPixels[0])
convexH = cv2.convexHull(np.asarray(textPixels))

# Find the side edges in the convex hull
m = []
for index in range((len(convexH))-1):

    # Calculate the angle of the line
    point0 = convexH[index]
    point1 = convexH[index+1]
    if(point1[0,0]-point0[0,0]) == 0:
        m.append(90)
    else:
        m.append(float((point1[0,1]-point0[0,1]))/float((point1[0,0]-point0[0,0])))

# Final line
point0 = convexH[index+1]
point1 = convexH[0]
if(point1[0,0]-point0[0,0]) == 0:
    m.append(90)
else:
    m.append(np.abs(float((point1[0,1]-point0[0,1]))/float((point1[0,0]-point0[0,0]))))

# Take all the lines with the big m
ind1 = np.where(np.asarray(m)>1)
ind2 = np.where(np.asarray(m)<-1)

# For both lines find min Y an max Y
yLines1,xLine1 = getConvexCoord(convexH,ind1)
yLines2,xLine2 = getConvexCoord(convexH,ind2)
yLines = yLines1 + yLines2

# Filter xLines. If we the difference between the min and the max are more than 1/2 the size of the image we filter it out
minY = np.min(np.asarray(yLines))
maxY = np.max(np.asarray(yLines))

maxX1,minX1 = filterLine(xLine1)
maxX2,minX2 = filterLine(xLine2)

# Change final lines to have minY and maxY
line1 = ((minX1,minY),(maxX1,maxY))
line2 = ((maxX2,minY),(minX2,maxY))

# Plot lines
IrgbWithLines = Irgb
cv2.line(IrgbWithLines,line1[0],line1[1],(0, 0, 255),2)
cv2.line(IrgbWithLines,line2[0],line2[1],(0, 0, 255),2)

备注: 该算法假定 y 坐标变化大于 x 坐标变化。对于非常高的透视变形(45 度),情况并非如此。在这种情况下,也许你应该在斜率上使用 k-means 并将具有较高斜率的组作为垂直线。

边上用红色标记的线可以使用图像闭合操作找到。 请在下面找到 imclose 操作后的 matlab 输出,结构元素类型为 square,大小为 4。'

matlab代码如下:

I = rgb2gray(imread('image.jpg')); 即时显示(我);标题('image');

Ibinary = im2bw(I); 图,imshow(Ibinary);

se = strel('square',4);

Iclose = imclose(Ibinary,se); 图,imshow(Iclose);标题('side lines');