|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import sys
- from pathlib import Path
- import math
- import cv2
- import numpy as np
- import torch
- import math
- import time
-
- FILE = Path(__file__).absolute()
- #sys.path.append(FILE.parents[0].as_posix()) # add yolov5/ to path
-
- def calculate_distance(point1, point2):
- """计算两个点之间的欧氏距离"""
- point= center_coordinate(point1)
- point=np.array(point)
- other_point = center_coordinate(point2)
- other_point = np.array(other_point)
- return np.linalg.norm(point - other_point)
-
- def find_clusters(preds, min_distance):
- """按照最小距离将点分成簇"""
- points=preds
- points=np.array(points)
- clusters = []
- used_points = set()
- for i, point in enumerate(points):
- if i not in used_points: # 如果该点未被使用过
- cluster = [point]
- used_points.add(i)
- # 寻找与该点距离小于等于min_distance的其他点
- for j, other_point in enumerate(points):
- if j not in used_points:
- if all(calculate_distance(point, other_point) <= min_distance
- for point in cluster):
- cluster.append(other_point)
- used_points.add(j)
- clusters.append(cluster)
- return clusters
-
- def center_coordinate(boundbxs):
- '''
- 根据检测矩形框,得到其矩形长度和宽度
- 输入:两个对角坐标xyxy
- 输出:矩形框重点坐标xy
- '''
- boundbxs_x1 = boundbxs[0]
- boundbxs_y1 = boundbxs[1]
- boundbxs_x2 = boundbxs[2]
- boundbxs_y2 = boundbxs[3]
- center_x = 0.5 * (boundbxs_x1 + boundbxs_x2)
- center_y = 0.5 * (boundbxs_y1 + boundbxs_y2)
- return [center_x, center_y]
-
- def get_bounding_rectangle(rectangles):
- '''
- 通过输入多个矩形的对角坐标,得到这几个矩形的外包矩形对角坐标
- 输入:点簇列表 (嵌套列表)
- 输出:多个矩形的外包矩形对角坐标 (列表)
- '''
- min_x, max_x, min_y, max_y = float('inf'), float('-inf'), float('inf'), float('-inf')
- for rect in rectangles:
- x1, y1, x2, y2,c1,t1 = rect
- min_x = min(min_x, min(x1, x2))
- max_x = max(max_x, max(x1, x2))
- min_y = min(min_y, min(y1, y2))
- max_y = max(max_y, max(y1, y2))
- return [min_x, min_y, max_x, max_y]
-
- def calculate_score(input_value):
- '''
- 计算人群聚集置信度,检测出3-10人内,按照0.85-1的上升趋势取值;
- 当检测超过10人,直接判断分数为1.
- '''
-
- if input_value == 3:
- output_value=0.85
- elif input_value == 4:
- output_value=0.9
- elif 5<= input_value <=10:
- output_value = 0.9+(input_value-4)*0.015
- else:
- output_value=1
- return output_value
-
-
- def gather_post_process(predsList, pars):
- '''
- 后处理程序,针对检测出的pedestrian,进行人员聚集的算法检测,按照类别'crowd_people'增加predsList
- ①原类别:
- ['ForestSpot', 'PestTree', 'pedestrian', 'fire', 'smog','cloud']=[0,1,2,3,4,5]
- ②处理后的类别汇总:
- ['ForestSpot', 'PestTree', 'pedestrian', 'fire', 'smog','cloud','crowd_people']=[0,1,2,3,4,5,6]
-
- 输入:
- preds 一张图像的检测结果,为嵌套列表,tensor,包括x_y_x_y_conf_class
- imgwidth,imgheight 图像的原始宽度及长度
- 输出:检测结果(将其中未悬挂国旗的显示)
- '''
- t0=time.time()
- predsList = predsList[0]
- predsList = [x for x in predsList if int(x[5]) !=5 ]##把类别“云朵”去除
- # 1、过滤掉类别2以外的目标,只保留行人
- preds = [ x for x in predsList if int(x[5]) ==pars['pedestrianId'] ]
-
-
- if len(preds)< pars['crowdThreshold']:
- return predsList,'gaher postTime:No gathering'
- preds = np.array(preds)
- longs = np.mean(np.max(preds[:,2:4]-preds[:,0:2]))
- distanceThreshold = pars['distancePersonScale']*longs
- # 2、查找点簇
- clusters = find_clusters(preds, distanceThreshold)
-
- clusters_crowd = []
- # 3、输出点簇信息,点簇中数量超过阈值,判断人员聚集
- for i, cluster in enumerate(clusters):
- if len(cluster) >= pars['crowdThreshold']: # 超过一定人数,即为人员聚集
- #print(f"Cluster {i + 1}: {len(cluster)} points")
- clusters_crowd.append(cluster)
- #print(clusters_crowd)
-
- # 4、根据得到的人员聚集点簇,合并其他类别检测结果
- for i in range(len(clusters_crowd)):
- xyxy = get_bounding_rectangle(clusters_crowd[i]) # 人群聚集包围框
- score = calculate_score(len(clusters_crowd[i])) # 人群聚集置信度
- xyxy.append(score) # 人群聚集置信度
- xyxy.append(pars['gatherId']) # 人群聚集类别
- predsList.append(xyxy)
-
- # 5、输出最终类别,共7类,用于绘图显示
- output_predslist = predsList
- #print('craoGaher line131:',output_predslist)
- t1=time.time()
-
- return output_predslist,'gaher postTime:%.1f ms'%( (t1-t0)*1000 )
-
- if __name__ == "__main__":
- t1 = time.time()
- # 对应vendor1_20240529_99.jpg检测结果
- preds=[[224.19933, 148.30751, 278.19156, 199.87828, 0.87625, 2.00000],
- [362.67139, 161.25760, 417.72357, 211.51706, 0.86919, 2.00000],
- [437.00131, 256.19083, 487.88870, 307.72897, 0.85786, 2.00000],
- [442.64606, 335.78168, 493.75720, 371.41418, 0.85245, 2.00000],
- [324.58362, 256.18488, 357.72626, 294.08929, 0.84512, 2.00000],
- [343.59781, 301.06506, 371.04105, 350.01086, 0.84207, 2.00000],
- [301.35858, 210.64088, 332.64862, 250.78883, 0.84063, 2.00000],
- [406.02994, 216.91214, 439.44455, 249.26077, 0.83698, 2.00000],
- [321.53494, 99.68467, 354.67477, 135.53226, 0.82515, 2.00000],
- [253.97131, 202.65234, 302.06055, 233.30634, 0.81498, 2.00000],
- [365.62521, 66.42108, 442.02292, 127.37558, 0.79556, 1.00000]]
- #preds=torch.tensor(preds) #返回的预测结果
- imgwidth=1920
- imgheight=1680
- pars={'imgSize':(imgwidth,imgheight),'pedestrianId':2,'crowdThreshold':4,'gatherId':6,'distancePersonScale':2.0}
- '''
- pedestrianId 为行人识别的类别;
- crowdThreshold为设置的判断人员聚集的人数阈值,默认4人为聚集
- distanceThreshold为设置的判断人员聚集的距离阈值,为了测试默认300像素内为聚集(可自行设置)
- '''
- yyy=gather_post_process(preds,pars) #送入后处理函数
- t2 = time.time()
- ttt = t2 - t1
- print('时间', ttt * 1000)
|