【问题标题】:How to sort contours left to right, while going top to bottom, using Python and OpenCV如何使用 Python 和 OpenCV 从左到右排序轮廓,同时从上到下排序
【发布时间】:2016-12-12 19:51:04
【问题描述】:

我正在寻找带有数字和字符的图像的轮廓,用于 OCR。所以,我需要从左到右对轮廓进行排序,同时逐行排序,即从上到下。现在,轮廓不是这样排序的。

例如,上图的轮廓是随机排序的。

我需要的是排序为 D,o,y,o,u,k,n,o,w,s,o,m,e,o,n,e,r,.(dot),i (不带点),c,h...等等。我尝试了几种方法,我们首先观察 y 坐标,然后使用一些键和 x 坐标。就像现在一样,我有以下排序代码。它适用于前 2 行。然后在第三行,排序不会发生。主要问题似乎出在诸如 i、j、?、(点)、(逗号)等字母中,其中(点)的 y 轴发生了变化,尽管属于同一行。那么有什么好的解决方案呢?

for ctr in contours:    
    if cv2.contourArea(ctr) > maxArea * areaRatio: 
        rect.append(cv2.boundingRect(cv2.approxPolyDP(ctr,1,True)))

#rect contains the contours
for i in rect:
    x = i[0]
    y = i[1]
    w = i[2]
    h = i[3]

    if(h>max_line_height):
        max_line_height = h

mlh = max_line_height*2
max_line_width = raw_image.shape[1] #width of the input image
mlw = max_line_width
rect = np.asarray(rect)
s = rect.astype( np.uint32 ) #prevent overflows
order= mlw*(s[:,1]/mlh)+s[:,0]
sort_order= np.argsort( order )
rect = rect[ sort_order ]

【问题讨论】:

  • 请提供一个清晰的示例,说明第 3 行中的问题。
  • 图像第三行的轮廓被排序为stress.ed,hav..i,n,g。等等。这些点随机出现在其他字母的位置,导致其他字母落在正确的排序位置。

标签: python sorting opencv contour


【解决方案1】:

我喜欢您尝试通过一次排序来解决问题。但正如您所说,每行中 y 的变化可能会破坏您的算法,另外,max_line_height 可能需要根据不同的输入进行调整。

因此,我会提出一个稍微不同的算法,但计算复杂度不错。这个想法是,如果你只看水平的所有框,从行N+1 的所有框将永远不会与从行1N 的框相交,但它们在一行内彼此相交。因此,您可以先按y 对所有框进行排序,逐个遍历它们并尝试找到“断点”(将它们分组为一行),然后在每一行中按x 对它们进行排序。

这是一个不那么 Pythonic 的解决方案:

# sort all rect by their y
rect.sort(key=lambda b: b[1])
# initially the line bottom is set to be the bottom of the first rect
line_bottom = rect[0][1]+rect[0][3]-1
line_begin_idx = 0
for i in xrange(len(rect)):
    # when a new box's top is below current line's bottom
    # it's a new line
    if rect[i][1] > line_bottom:
        # sort the previous line by their x
        rect[line_begin_idx:i] = sorted(rect[line_begin_idx:i], key=lambda b: b[0])
        line_begin_idx = i
    # regardless if it's a new line or not
    # always update the line bottom
    line_bottom = max(rect[i][1]+rect[i][3]-1, line_bottom)
# sort the last line
rect[line_begin_idx:] = sorted(rect[line_begin_idx:], key=lambda b: b[0])

现在rect 应该按照您想要的方式排序。

【讨论】:

    【解决方案2】:

    我使用了这种方法,它对我有用。 就我而言,每行有 5 个轮廓

    def x_cord_contour(contours):
        #Returns the X cordinate for the contour centroid
        M = cv2.moments(contours)
        return (int(M['m10']/M['m00']))
        
    def y_cord_contour(contours):
        #Returns the Y cordinate for the contour centroid
        M = cv2.moments(contours)
        return (int(M['m01']/M['m00']))
        
    
    # Sort by top to bottom using our y_cord_contour function
    contours_top_to_bottom = sorted(questionCnts, key = y_cord_contour, reverse = False)
    
    
    
    
    
    for (q, i) in enumerate(np.arange(0, len(contours_top_to_bottom), 5)):
        # sort the contours for the current question from left to right
        
        # As in my example every row contain 5 coutours so now i sorted them in row wise
        cnts = sorted(contours_top_to_bottom[i:i + 5], key = x_cord_contour, reverse = False)
        
        # loop over the sorted contours
        for (j, c) in enumerate(cnts):
            # construct a mask that reveals only the current contour
            #and do what ever you want to do
            #....#
    

    如果我错了请纠正我

    【讨论】:

      猜你喜欢
      • 2016-12-03
      • 2015-01-24
      • 1970-01-01
      • 2021-08-08
      • 1970-01-01
      • 2017-01-17
      • 2022-09-24
      • 2014-08-23
      • 2015-06-20
      相关资源
      最近更新 更多