我找到了带有数字和字符的图像的轮廓,用于OCR。因此,我需要从左到右排序轮廓,同时逐行排列,即从上到下排列。现在,轮廓没有那样排序。
例如,上面图像的轮廓是随机排序的。
我需要的是排序为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 ]
答案 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
中的所有框都不会与行1
到N
的框相交,但它们与每个框相交其他一行内。因此,您可以先按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])
进行排序。