状态类算法复杂排序输出

对于目标检测任务中对某一类的检测结果进行输出的时候,一般都是无序的,很明显这样子很难满足的我们的需求,我们更喜欢他是这样子输出的:

👇 

我们可以看到——”按顺序输出结果“中的字段是完美的和上面图片中的识别结果一一对应的,这其实也很容易做到。

我们只需要把这些个矩形框一个个抽出来,放在一张白纸上面,如下图所示:

NOTE:下图是模拟的复杂样例,并非上图中的矩形框抽出来。

红色箭头代表的就是正确的排序方式,看到这里有一些朋友可能已经有了思路,我这边使用了数据结构算法中的图论算法,我们可以把上面四个箭头当作四层, 每一层从根节点也就是最左边的矩形框出发进行连边操作,每一次连边必须满足以下要求:

  • 连边的矩形框与上一个节点的Iou!=0
  • 连边的矩形框的质心必须处于上一个节点质心的右边
  • 连边的矩形框的质心必须与上一个节点的质心有着距离最近的关系。

根据这些约束条件,我们可以选取最左上的节点当作第一层的根节点,开始我们的连边操作:

当最有一个节点的最右边已经没有了节点的时候,至此我们结束了第一层搜索,删掉第一层连接的所有矩形框,进入第二层搜索。由于删掉了第一层所有的矩形框,第二层的第一个节点又变成了最左上角的节点,选取她开始第二轮的遍历连边操作。

以此类推,我们便完成了所有排序的工作:

放上一些彩蛋图: 

🍉参考实现代码如下:

from collections import deque
import mathdef 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.0center_y = (ymin + ymax) / 2.0return (int(center_x),int(center_y))def cal_dist(point1, point2):x1, y1 = point1x2, y2 = point2distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)return distancedef cal_xIou(ret1, ret2):x1,y1 = convert_to_center(*ret1)x2,y2 = convert_to_center(*ret2)xmin1,ymin1,xmax1,ymax1 = ret1xmin2,ymin2,xmax2,ymax2 = ret2# print(ymin1, ymin2, ymax1, ymax2)if ymax1 < ymin2 or ymax2 < ymin1:return Falseelse: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):continueshortest_dist = disttarget = iter_point          return targetdef 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, 0for 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] = 1result = {}queue = []seen = set()start_point = min(centres_coordinates, key=lambda point: (point[0], -point[1]))queue.append(start_point)seen.add(start_point)layer = 1iter_idx = 1print("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=Trueif iter_point[0]==-1:judge = Falseif judge:queue.append(iter_point)iter_idx += 1seen.add(iter_point)else:result[layer] = queueif iter_idx == length_data:breaklayer += 1for 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 += 1print("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])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/239122.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

u盘一插上就提示格式化解决办法,帮助重新使用,避免数据丢失

在我们使用U盘的过程中&#xff0c;有时会遇到一插上就提示格式化的问题。这个问题可能会给我们带来很多麻烦&#xff0c;因为格式化操作会导致数据的丢失。为了解决这一问题&#xff0c;本文将介绍一些解决办法&#xff0c;帮助读者重新使用U盘&#xff0c;并避免数据丢失的风…

树莓派4b安装ubuntu22和向日葵设置开机启动

树莓派4b安装ubuntu22和向日葵设置开机启动 使用树莓派烧录系统工具烧录ubuntu 在树莓派官网下载官方软件&#xff0c;安装完后运行 在软件上选择 选择ubuntu桌面或者server 根据自己需求选择&#xff0c;这里我选择22.04的系统 烧录好以后进入系统 安装向日葵 下载树莓…

优彩云采集器最新版免费下载,优彩云采集器免费

随着网络时代的发展&#xff0c;SEO&#xff08;Search Engine Optimization&#xff0c;搜索引擎优化&#xff09;已经成为网站推广和营销的关键一环。在SEO的世界里&#xff0c;原创内容的重要性愈发凸显。想要做到每天更新大量原创文章&#xff0c;并不是一件轻松的事情。优…

【数电笔记】最小项(逻辑函数的表示方法及其转换)

目录 说明&#xff1a; 逻辑函数的建立 1. 分析逻辑问题&#xff0c;建立逻辑函数的真值表 2. 根据真值表写出逻辑式 3. 画逻辑图 逻辑函数的表示 1. 逻辑表达式的常见表示形式与转换 2. 逻辑函数的标准表达式 &#xff08;1&#xff09;最小项的定义 &#xff08;2&am…

VLAN间路由详细讲解

本次实验拓扑的主要概述以及设计到的相关技术 VLAN技术&#xff1a; VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网&#xff0c;是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。 每个VLAN是一个广播域&#xff0c;VLAN内的主机间可以直…

【开源】基于Vue和SpringBoot的校园二手交易系统

项目编号&#xff1a; S 009 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S009&#xff0c;文末获取源码。} 项目编号&#xff1a;S009&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手商品档案管理模…

springboot + vue 智能物流管理系统

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

牛客小白月赛82(A~C)

目录 A.谜题&#xff1a;质数 输入描述 输出描述 输入 输出 解析 B.Kevin逛超市 2 (简单版本) 输入描述 输出描述 输入 输出 思路 C.被遗忘的书籍 题目描述 输入描述 输出描述 输入 输出 输入 输出 思路 比赛链接 牛客小白月赛82_ACM/NOI/CSP/CCPC/ICPC算…

YOLOv8优化策略:SENetV2,squeeze和excitation全面升级,效果优于SENet | 2023年11月最新成果

🚀🚀🚀本文改进: SENetV2,squeeze和excitation全面升级,作为注意力机制引入到YOLOv8,放入不同网络位置实现涨点 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1.SENetV2 论文:https://arxiv.org/…

【WPF.NET开发】WPF.NET桌面应用开发概述

本文内容 为何从 .NET Framework 升级使用 WPF 进行编程标记和代码隐藏输入和命令控件布局数据绑定图形和动画文本和版式自定义 WPF 应用 Windows Presentation Foundation (WPF) 是一个与分辨率无关的 UI 框架&#xff0c;使用基于矢量的呈现引擎&#xff0c;构建用于利用现…

版本控制系统Git学习笔记-Git分支操作

文章目录 概述一、Git分支简介1.1 基本概念1.2 创建分支1.3 分支切换1.4 删除分支 二、新建和合并分支2.1 工作流程示意图2.2 新建分支2.3 合并分支2.4 分支示例2.4.1 当前除了主分支&#xff0c;再次创建了两个分支2.4.2 先合并test1分支2.4.3 合并testbranch分支 2.5 解决合并…

利用socket打造一个聊天室

下面是一个简单的JavaFX聊天应用程序的实现。 创建项目并添加依赖 首先创建一个新的JavaFX项目。在pom.xml文件中添加以下依赖项&#xff1a; <dependencies><dependency><groupId>org.openjfx</groupId><artifactId>javafx-controls</art…