我正在尝试使用Python构建一个字符识别程序。我被困在整理轮廓。我使用constructor作为参考。
我设法使用以下代码找到轮廓:
mo_image = di_image.copy()
contour0 = cv2.findContours(mo_image.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
contours = [cv2.approxPolyDP(cnt,3,True) for cnt in contour0[0]]
并添加了边界矩形并使用以下代码部分对图像进行分割:
maxArea = 0
rect=[]
for ctr in contours:
maxArea = max(maxArea,cv2.contourArea(ctr))
if img == "Food.jpg":
areaRatio = 0.05
elif img == "Plate.jpg":
areaRatio = 0.5
for ctr in contours:
if cv2.contourArea(ctr) > maxArea * areaRatio:
rect.append(cv2.boundingRect(cv2.approxPolyDP(ctr,1,True)))
symbols=[]
for i in rect:
x = i[0]
y = i[1]
w = i[2]
h = i[3]
p1 = (x,y)
p2 = (x+w,y+h)
cv2.rectangle(mo_image,p1,p2,255,2)
image = cv2.resize(mo_image[y:y+h,x:x+w],(32,32))
symbols.append(image.reshape(1024,).astype("uint8"))
testset_data = np.array(symbols)
cv2.imshow("segmented",mo_image)
plt.subplot(2,3,6)
plt.title("Segmented")
plt.imshow(mo_image,'gray')
plt.xticks([]),plt.yticks([]);
但是,结果段显示为随机顺序。 这是原始图像,后面是带有检测到的段的已处理图像。
然后程序会单独输出每个细分,但顺序为:4 1 9 8 7 5 3 2 0 6
而不是0 1 2 3 4 5 6 7 8 9
。
简单地在“rect”中添加排序操作可以解决这个问题,但是对于包含多行的文档,同样的解决方案不适用。
所以我的问题是:如何从左到右,从上到下对轮廓进行排序?
答案 0 :(得分:2)
def sort_contours(contours, x_axis_sort='LEFT_TO_RIGHT', y_axis_sort='TOP_TO_BOTTOM'):
# initialize the reverse flag
x_reverse = False
y_reverse = False
if x_axis_sort == 'RIGHT_TO_LEFT':
x_reverse = True
if y_axis_sort == 'BOTTOM_TO_TOP':
y_reverse = True
boundingBoxes = [cv2.boundingRect(c) for c in contours]
# sorting on x-axis
sortedByX = zip(*sorted(zip(contours, boundingBoxes),
key=lambda b:b[1][0], reverse=x_reverse))
# sorting on y-axis
(contours, boundingBoxes) = zip(*sorted(zip(*sortedByX),
key=lambda b:b[1][1], reverse=y_reverse))
# return the list of sorted contours and bounding boxes
return (contours, boundingBoxes)
contours, hierarchy = cv2.findContours(img_vh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours, boundingBoxes = sort_contours(contours, x_axis_sort='LEFT_TO_RIGHT', y_axis_sort='TOP_TO_BOTTOM')
答案 1 :(得分:1)
我认为您不能以正确的顺序直接生成轮廓,但如下所示的简单排序应该可以满足您的需求:
import numpy as np
c = np.load(r"rect.npy")
contours = list(c)
# Example - contours = [(287, 117, 13, 46), (102, 117, 34, 47), (513, 116, 36, 49), (454, 116, 32, 49), (395, 116, 28, 48), (334, 116, 31, 49), (168, 116, 26, 49), (43, 116, 30, 48), (224, 115, 33, 50), (211, 33, 34, 47), ( 45, 33, 13, 46), (514, 32, 32, 49), (455, 32, 31, 49), (396, 32, 29, 48), (275, 32, 28, 48), (156, 32, 26, 49), (91, 32, 30, 48), (333, 31, 33, 50)]
max_width = np.sum(c[::, (0, 2)], axis=1).max()
max_height = np.max(c[::, 3])
nearest = max_height * 1.4
contours.sort(key=lambda r: (int(nearest * round(float(r[1])/nearest)) * max_width + r[0]))
for x, y, w, h in contours:
print "{:4} {:4} {:4} {:4}".format(x, y, w, h)
这将显示以下输出:
36 45 33 40
76 44 29 43
109 43 29 45
145 44 32 43
184 44 21 43
215 44 21 41
241 43 34 45
284 46 31 39
324 46 7 39
337 46 14 41
360 46 26 39
393 46 20 41
421 45 45 41
475 45 32 41
514 43 38 45
39 122 26 41
70 121 40 48
115 123 27 40
148 121 25 45
176 122 28 41
212 124 30 41
247 124 91 40
342 124 28 39
375 124 27 39
405 122 27 43
37 210 25 33
69 199 28 44
102 210 21 33
129 199 28 44
163 210 26 33
195 197 16 44
214 210 27 44
247 199 25 42
281 212 7 29
292 212 11 42
310 199 23 43
340 199 7 42
355 211 43 30
406 213 24 28
437 209 31 35
473 210 28 43
506 210 28 43
541 210 17 31
37 288 21 33
62 282 15 39
86 290 24 28
116 290 72 30
192 290 23 30
218 290 26 41
249 288 20 33
它的工作原理是对相似的y
值进行分组,然后乘以宽度,结果是逐行增加的键。计算单个矩形的最大高度以确定nearest
的合适分组值。 1.4
值是行间距值。这也可以自动计算。因此,对于您的两个示例nearest
约为70。
计算也可以直接在numpy中完成。
答案 2 :(得分:1)
当我完成任务时,我采取了这种方法(我认为这种方法尚未优化,可以改进):
import pandas as pd
import cv2
import cv2
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize'] = (20.0, 10.0)
matplotlib.rcParams['image.cmap'] = 'gray'
imageCopy = cv2.imread("./test.png")
imageGray = cv2.imread("./test.png", 0)
image = imageCopy.copy()
contours, hierarchy = cv2.findContours(imageGray, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
bboxes = [cv2.boundingRect(i) for i in contours]
bboxes=sorted(bboxes, key=lambda x: x[0])
df=pd.DataFrame(bboxes, columns=['x','y','w', 'h'], dtype=int)
df["x2"] = df["x"]+df["w"] # adding column for x on the right side
df = df.sort_values(["x","y", "x2"]) # sorting
for i in range(2): # change rows between each other by their coordinates several times
# to sort them completely
for ind in range(len(df)-1):
# print(ind, df.iloc[ind][4] > df.iloc[ind+1][0])
if df.iloc[ind][4] > df.iloc[ind+1][0] and df.iloc[ind][1]> df.iloc[ind+1][1]:
df.iloc[ind], df.iloc[ind+1] = df.iloc[ind+1].copy(), df.iloc[ind].copy()
num=0
for box in df.values.tolist():
x,y,w,h, hy = box
cv2.rectangle(image, (x,y), (x+w,y+h), (255,0,255), 2)
# Mark the contour number
cv2.putText(image, "{}".format(num + 1), (x+40, y-10), cv2.FONT_HERSHEY_SIMPLEX, 1,
(0, 0, 255), 2);
num+=1
plt.imshow(image[:,:,::-1])
答案 3 :(得分:1)
给定一个二值图像 - thresh
,我认为最短的方法是 -
import numpy as np
import cv2
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NON) #thresh is a bia
cntr_index_LtoR = np.argsort([cv2.boundingRect(i)[0] for i in contours])
此处,cv2.boundingRect(i)[0]
仅从 x
返回 x,y,w,h = cv2.boundingRect(i)
第 i
个轮廓。
同样,您可以使用从上到下。
答案 4 :(得分:0)
contours.sort(key=lambda r: round( float(r[1] / nearest)))
会产生类似(int(nearest * round(float(r[1])/nearest)) * max_width + r[0])
答案 5 :(得分:0)
使用contours=cv2.findContours()
找到轮廓后,使用-
boundary=[]
for c,cnt in enumerate(contours):
x,y,w,h = cv2.boundingRect(cnt)
boundary.append((x,y,w,h))
count=np.asarray(boundary)
max_width = np.sum(count[::, (0, 2)], axis=1).max()
max_height = np.max(count[::, 3])
nearest = max_height * 1.4
ind_list=np.lexsort((count[:,0],count[:,1]))
c=count[ind_list]
现在c将从左到右,从上到下排序。
答案 6 :(得分:0)
用从左到右,从上到下的轮廓的边界框(x,y,w,h)对轮廓进行排序的简单方法如下。
您可以使用 boundingBoxes = cv2.boundingRect() 方法获取边界框
def sort_bbox(boundingBoxes):
'''
function to sort bounding boxes from left to right, top to bottom
'''
# combine x and y as a single list and sort based on that
boundingBoxes = sorted(boundingBoxes, key=lambda b:b[0]+b[1], reverse=False))
return boundingboxes
该方法并未在所有案例中进行广泛测试,但发现对我正在做的项目非常有效。
链接到排序函数文档以供参考https://docs.python.org/3/howto/sorting.html