我在回答这个问题:
How can I sort contours from left to right and top to bottom?
从左到右和从上到下对轮廓进行排序。但是,我的轮廓是用这个(OpenCV 3)找到的:
im2, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
它们的格式如下:
array([[[ 1, 1]],
[[ 1, 36]],
[[63, 36]],
[[64, 35]],
[[88, 35]],
[[89, 34]],
[[94, 34]],
[[94, 1]]], dtype=int32)]
当我运行代码时
max_width = max(contours, key=lambda r: r[0] + r[2])[0]
max_height = max(contours, key=lambda r: r[3])[3]
nearest = max_height * 1.4
contours.sort(key=lambda r: (int(nearest * round(float(r[1])/nearest)) * max_width + r[0]))
我明白了
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
所以我改成这样:
max_width = max(contours, key=lambda r: np.max(r[0] + r[2]))[0]
max_height = max(contours, key=lambda r: np.max(r[3]))[3]
nearest = max_height * 1.4
contours.sort(key=lambda r: (int(nearest * round(float(r[1])/nearest)) * max_width + r[0]))
但现在我发现了一个错误:
TypeError: only length-1 arrays can be converted to Python scalars
编辑:
在阅读了下面的答案后,我修改了代码:
编辑2
这是我用来“放大”字符并找到轮廓的代码
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(35,35))
# dilate the image to get text
# binaryContour is just the black and white image shown below
dilation = cv2.dilate(binaryContour,kernel,iterations = 2)
编辑2结束
im2, contours, hierarchy = cv2.findContours(dilation,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
myContours = []
# Process the raw contours to get bounding rectangles
for cnt in reversed(contours):
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
if len(approx == 4):
rectangle = cv2.boundingRect(cnt)
myContours.append(rectangle)
max_width = max(myContours, key=lambda r: r[0] + r[2])[0]
max_height = max(myContours, key=lambda r: r[3])[3]
nearest = max_height * 1.4
myContours.sort(key=lambda r: (int(nearest * round(float(r[1])/nearest)) * max_width + r[0]))
i=0
for x,y,w,h in myContours:
letter = binaryContour[y:y+h, x:x+w]
cv2.rectangle(binaryContour,(x,y),(x+w,y+h),(255,255,255),2)
cv2.imwrite("pictures/"+str(i)+'.png', letter) # save contour to file
i+=1
排序前轮廓:
[(1, 1, 94, 36), (460, 223, 914, 427), (888, 722, 739, 239), (35,723, 522, 228),
(889, 1027, 242, 417), (70, 1028, 693, 423), (1138, 1028, 567, 643),
(781, 1030, 98, 413), (497, 1527, 303, 132), (892, 1527, 168, 130),
(37, 1719, 592, 130), (676, 1721, 413, 129), (1181, 1723, 206, 128),
(30, 1925, 997, 236), (1038, 1929, 170, 129), (140, 2232, 1285, 436)]
排序后的等高线:
(注意:这不是我想要的等高线排序顺序。参考下面的图片)
[(1, 1, 94, 36), (460, 223, 914, 427), (35, 723, 522, 228), (70,1028, 693, 423),
(781, 1030, 98, 413), (888, 722, 739, 239), (889, 1027, 242, 417),
(1138, 1028, 567, 643), (30, 1925, 997, 236), (37, 1719, 592, 130),
(140, 2232, 1285, 436), (497, 1527, 303, 132), (676, 1721, 413, 129),
(892, 1527, 168, 130), (1038, 1929, 170, 129), (1181, 1723, 206, 128)]
我正在处理的图像
实际上,您需要设计一个公式,将您的轮廓信息转换为列组并使用该列组对轮廓进行排序,因为您需要从上到下和从左到右对轮廓进行排序,所以您的公式必须包含给定轮廓的
origin
以计算其列组。例如,我们可以使用这个简单的方法:它根据轮廓的原点给每个轮廓赋予一个等级。当两个连续的等高线垂直放置时,其变化很大,但当等高线水平堆叠时,其变化很小。这样,首先将轮廓从上到下进行分组,如果发生冲突,将使用水平布局轮廓之间变化较小的值。
如果仔细观察,第三行
3, 4, 5, 6
等高线位于6
3和5之间,原因是第6
等高线略低于3, 4, 5
等高线。告诉我你想用其他方式输出我们可以调整
get_contour_precedence
以获得3, 4, 5, 6
级别的轮廓校正。这是Adrian Rosebrock提供的,用于根据位置link对等高线进行排序:
似乎链接的question不适用于原始轮廓,而是首先使用
cv2.boundingRect
获得一个边界矩形。只有这样,计算max_width
和max_height
才有意义。您发布的代码表明您正在尝试对原始轮廓进行排序,而不是对边界矩形进行排序。如果不是这样,你能提供一个更完整的代码片段,包括一个你试图排序的多个轮廓的列表吗?相关问题 更多 >
编程相关推荐