如何以一致的方式从左到右以及从上到下对轮廓进行排序 [英] How can I sort contours from left to right and top to bottom in a consistent manner
问题描述
我正在研究一个从图像中提取矩形框并按顺序对这些矩形框进行排序的问题.我尝试过的代码是:
I am working on a problem that extracts rectangular boxes from image and sort those rectangular boxes sequentially. Code that I tried is:
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的框.上面的代码以随机顺序提取框,有时是从左到右,有时是从右到左.
Image used to detect and extract contours: here. I want to extract the boxes containing numbers in order 1-2-3-4-5-6-7-----32. The above code extracts boxes in random order, sometimes from left-to-right and sometimes from right-to-left.
[已编辑]产生轮廓的图像顺序为4-3-2-1 8-7-6-5 ... 1 2
产生轮廓的图像顺序为1-2-3-4 5-6-7-8 ... 3 5
Images that yield contour in order 4-3-2-1 8-7-6-5...
1
2
Images that yield contour in order 1-2-3-4 5-6-7-8...
3
5
推荐答案
是纸张的方向-或:旋转-决定是否简单地检查(x,y)
坐标轮廓的边界框是否足够.
It's the orientation – or: the rotation – of the paper, that decides, whether simply checking the (x, y)
coordinates of the contours' bounding boxes is sufficient or not.
因此,我只是坚持使用一些好的旧比较方法,例如我先前对C ++中实现的同一问题的回答.不幸的是,使用旧方法在Python 3中完全删除了 sorted
中的 cmp
参数.但是,我们可以从 functools中使用
cmp_to_key
模块,以将该功能映射到适当的 key
函数.
So, I'd simply stick to some good old comparison method, e.g. this earlier answer from me on the same issue implemented in C++. Unfortunately, using the old way using the cmp
parameter in sorted
was removed entirely in Python 3. Nevertheless, we can use cmp_to_key
from the functools
module to get that functionality mapped to a proper key
function.
现在,首先,我们创建比较方法:
Now, first, let's create the comparison method:
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
(或其他任何适当的阈值)
The abs(...) <= 15
(or any other proper threshold) is needed for the cases, where the right boxes are higher than the left boxes (i.e. the main problem).
然后,将此行添加到您的导入中:
Then, add this line to your imports:
from functools import cmp_to_key
最后,在您的 sorted
调用中替换 key
函数:
Finally, replace the key
function in your sorted
call to that:
cnts = sorted(cnts, key=cmp_to_key(contour_sort))
这样做,我可以为所有给定的图像提取正确的顺序.
Doing so, I can extract the correct order for all the given images.
如果有人可以提供简单的 key
函数而无需比较方法,那么我对此会非常感兴趣!我自己找不到一个人.
If someone can provide a simple key
function without the need of a comparison method, I'd be very interested in that! I couldn't find one myself.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.8.5
OpenCV: 4.5.1
----------------------------------------
这篇关于如何以一致的方式从左到右以及从上到下对轮廓进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!