如何使用Python和OpenCV

时间:2016-08-06 14:42:17

标签: python sorting opencv contour

我找到了带有数字和字符的图像的轮廓,用于OCR。因此,我需要从左到右排序轮廓,同时逐行排列,即从上到下排列。现在,轮廓没有那样排序。

picture

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

我需要的是排序为D,o,y,o,u,k,n,o,w,s,o,m,e,o,n,e,r ,.(dot),i (没有点),c,h ......等等。我已经尝试了几种方法,我们首先观察y坐标,然后使用一些键和x坐标。就像现在一样,我有以下排序代码。它适用于前两行。然后在第3行,排序以某种方式不会发生。主要问题似乎是在诸如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 ]

2 个答案:

答案 0 :(得分: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
        #....#

如果我写错了请纠正我

答案 1 :(得分:0)

我喜欢你试图通过单一排序解决问题。但正如你所说,每行中y的变化可能会破坏你的算法,而且max_line_height是你可能需要根据不同的输入调整的。

相反,我会提出一个略有不同的算法,但计算复杂度不错。我们的想法是,如果您只是水平查看所有框,则行N+1中的所有框都不会与行1N的框相交,但它们与每个框相交其他一行内。因此,您可以先按y对所有方框进行排序,逐个浏览它们,然后尝试找到“断点”(将它们分成一行),然后在每一行中按{{1}对它们进行排序}}

这是一个较少的Pythonic解决方案:

x

现在应该按照您想要的方式对# 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]) 进行排序。