如何以一致的方式从左到右、从上到下对轮廓进行排序?



我正在研究一个从图像中提取矩形框并按顺序对这些矩形框进行排序的问题。我尝试的代码是:

import cv2
import matplotlib.pyplot as plt
# Load image, grayscale, adaptive threshold
image = cv2.imread('3.jpg')
result = image.copy()
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,51,9)
# Fill rectangular contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(thresh, [c], -1, (255,255,255), -1)
# Morph open
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=4)
plt.imshow(thresh)
# Draw rectangles
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=lambda x: [cv2.boundingRect(x)[1], cv2.boundingRect(x)[0]])
# cnts = sorted(cnts, key=lambda ctr: cv2.boundingRect(ctr)[0] + cv2.boundingRect(ctr)[1] * image.shape[1], reverse=True)
i = 0
for c in cnts:
area = cv2.contourArea(c)
#     print("Area:", area)
x,y,w,h = cv2.boundingRect(c)

#     cv2.rectangle(image, (x+8, y+8), (x + w-8, y + h-8), (36,255,12), 1)
roi = image[y:y+h, x:x+w]
cv2.imwrite('{}.jpg'.format(i), roi)
i += 1

cv2.imwrite('output_image.jpg', image)
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.waitKey()
cv2.destroyAllWindows()

用于检测和提取轮廓的图像:这里。我想取出顺序为1-2-3-4-5-6-7-----32的盒子。上面的代码以随机顺序提取盒子,有时从左到右,有时从右到左。

[编辑]生成等高线的图像按顺序为4-3-3 -1 8-7-6-5…12
按顺序1-2-3-4 - 5-6-7-8…3.5

这是纸张的方向-或:旋转-决定,是否仅仅检查轮廓的边界框的(x, y)坐标是足够的。

所以,我会简单地坚持一些好的老比较方法,例如我之前对c++中实现的相同问题的回答。不幸的是,在sorted中使用cmp参数的旧方法在Python 3中被完全删除了。然而,我们可以使用functools模块中的cmp_to_key来将该功能映射到适当的key功能。

现在,首先让我们创建比较方法:

def contour_sort(a, b):
br_a = cv2.boundingRect(a)
br_b = cv2.boundingRect(b)
if abs(br_a[1] - br_b[1]) <= 15:
return br_a[0] - br_b[0]
return br_a[1] - br_b[1]

需要abs(...) <= 15(或任何其他适当的阈值),在这种情况下,右框高于左框(即主要问题)。

然后,将这一行添加到您的导入中:

from functools import cmp_to_key

最后,将sorted调用中的key函数替换为:

cnts = sorted(cnts, key=cmp_to_key(contour_sort))

这样做,我可以提取所有给定图像的正确顺序。

如果有人能提供一个简单的key函数而不需要比较方法,我会非常感兴趣的!我自己也找不到。

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.8.5
OpenCV:        4.5.1
----------------------------------------

最新更新