对于目标检测任务中对某一类的检测结果进行输出的时候,一般都是无序的,很明显这样子很难满足的我们的需求,我们更喜欢他是这样子输出的:
我们可以看到——”按顺序输出结果“中的字段是完美的和上面图片中的识别结果一一对应的,这其实也很容易做到。
我们只需要把这些个矩形框一个个抽出来,放在一张白纸上面,如下图所示:
NOTE:下图是模拟的复杂样例,并非上图中的矩形框抽出来。
红色箭头代表的就是正确的排序方式,看到这里有一些朋友可能已经有了思路,我这边使用了数据结构算法中的图论算法,我们可以把上面四个箭头当作四层, 每一层从根节点也就是最左边的矩形框出发进行连边操作,每一次连边必须满足以下要求:
根据这些约束条件,我们可以选取最左上的节点当作第一层的根节点,开始我们的连边操作:
当最有一个节点的最右边已经没有了节点的时候,至此我们结束了第一层搜索,删掉第一层连接的所有矩形框,进入第二层搜索。由于删掉了第一层所有的矩形框,第二层的第一个节点又变成了最左上角的节点,选取她开始第二轮的遍历连边操作。
以此类推,我们便完成了所有排序的工作:
放上一些彩蛋图:
参考实现代码如下:
from collections import deque
import math
def draw(points):
import matplotlib.pyplot as plt
# 中心点坐标
# points = [(67.0, 72.0), (172.5, 70.0), (274.5, 79.5), (380.0, 79.0), (489.5, 149.5), (73.5, 241.0),
# (185.0, 249.0), (386.5, 239.0), (604.5, 128.5), (719.5, 151.0), (209.5, 403.0), (374.0, 393.0),
# (180.5, 562.0), (288.5, 568.5), (394.5, 573.5)]
# 提取 x 和 y 坐标
x_coords, y_coords = zip(*points)
# 创建一个散点图
plt.scatter(x_coords, y_coords, marker='o', color='blue')
# 添加坐标标签
for i, point in enumerate(points):
plt.annotate(f"{i, point}", (x_coords[i], y_coords[i]), textcoords="offset points", xytext=(0,10), ha='center', fontsize=8)
# 设置图的标题和坐标轴标签
plt.title("centre plot")
plt.xlabel("X")
plt.ylabel("Y")
# 设置坐标轴原点为左上角
plt.gca().invert_yaxis()
# 显示图
plt.grid()
plt.show()
plt.savefig("switch_sort.jpg",dpi=300)
def convert_to_center(xmin, ymin, xmax, ymax):
center_x = (xmin + xmax) / 2.0
center_y = (ymin + ymax) / 2.0
return (int(center_x),int(center_y))
def cal_dist(point1, point2):
x1, y1 = point1
x2, y2 = point2
distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
return distance
def cal_xIou(ret1, ret2):
x1,y1 = convert_to_center(*ret1)
x2,y2 = convert_to_center(*ret2)
xmin1,ymin1,xmax1,ymax1 = ret1
xmin2,ymin2,xmax2,ymax2 = ret2
# print(ymin1, ymin2, ymax1, ymax2)
if ymax1 < ymin2 or ymax2 < ymin1:
return False
else:
return True
# def find_right_shortestPoint(centres_coordinates, now_point):
# shortest_dist = float('inf')
# for iter_point in centres_coordinates:
# dist = cal_dist(now_point, iter_point)
# if dist < shortest_dist and dist != 0:
# if now_point[1] < iter_point[1]:
# return iter_point
# return ValueError("找不到距离最近的框,是不是总共只有一个框!")
def find_shortestPoint(bboxes, centres_coordinates, backup_centres_coordinates, now_point, seen):
shortest_dist = float('inf')
target=(-1,-1)
for iter_point in centres_coordinates:
if iter_point in seen:
continue
# print(now_point, iter_point)
if now_point[0] < iter_point[0]:
dist = cal_dist(now_point, iter_point)
# print(dist)
if dist < shortest_dist and dist != 0:
nowPoint_idx = backup_centres_coordinates.index(now_point)
iterPoint_idx = backup_centres_coordinates.index(iter_point)
nowBbox = bboxes[nowPoint_idx]
iterBbox = bboxes[iterPoint_idx]
# print(nowBbox, iterBbox)
if not cal_xIou(nowBbox, iterBbox):
continue
shortest_dist = dist
target = iter_point
return target
def main_layers(bboxes):
#[ [xmin,ymin,xmax,ymax]]
backup_bboxes = bboxes.copy()
centres_coordinates = []
for bbox in bboxes:
centre = convert_to_center(*bbox)
centres_coordinates.append(centre)
length_data = len(bboxes)
backup_centres_coordinates = centres_coordinates.copy()
# backup_centres_coordinates = centres_coordinates.copy()
max_h, max_w = 0, 0
for cc in centres_coordinates:
max_h = max(max_h, cc[0])
max_w = max(max_h, cc[1])
# draw(centres_coordinates)
grap = [[0 for _ in range(int(max_w + 10))] for _ in range(int(max_h) + 10)]
for cen in centres_coordinates:
cen_x, cen_y = int(cen[0]), int(cen[1])
grap[cen_x][cen_y] = 1
result = {
}
queue = []
seen = set()
start_point = min(centres_coordinates, key=lambda point: (point[0], -point[1]))
queue.append(start_point)
seen.add(start_point)
layer = 1
iter_idx = 1
print("Now Layer:{} start point:{}".format(layer, start_point))
while iter_idx <= length_data:
now_point = queue[-1]
iter_point = find_shortestPoint(backup_bboxes, centres_coordinates, backup_centres_coordinates,now_point, seen)
judge=True
if iter_point[0]==-1:
judge = False
if judge:
queue.append(iter_point)
iter_idx += 1
seen.add(iter_point)
else:
result[layer] = queue
if iter_idx == length_data:
break
layer += 1
for q in queue:
# print(q)
# print(centres_coordinates)
# backup_bboxes.remove(centres_coordinates.index(q))
centres_coordinates.remove(q)
queue = []
seen = set()
start_point = min(centres_coordinates, key=lambda point: (point[0], -point[1]))
queue.append(start_point)
seen.add(start_point)
iter_idx += 1
print("Now Layer:{} start point:{}".format(layer, start_point))
sorted_dict = dict(sorted(result.items(),key=lambda item: item[1][0][1]))
for key in sorted_dict:
print(key, sorted_dict[key])
return sorted_dict
使用方法:
bboxes = [[box[0], box[1], box[0]+box[2], box[1]+box[3]] for box in used_res]
sorted_dict = main_layers(bboxes)
centres_coordinates = []
for bbox in bboxes:
centre = convert_to_center(*bbox)
centres_coordinates.append(centre)
sorted_used_res = []
for layer in sorted_dict:
for iter_column in sorted_dict[layer]:
iter_index = centres_coordinates.index(iter_column)
sorted_used_res.append(used_res[iter_index])