compliance.py 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. ##################################################################
  4. #
  5. # Copyright (c) 2023 CICV, Inc. All Rights Reserved
  6. #
  7. ##################################################################
  8. """
  9. @Authors: xieguijin(xieguijin@china-icv.cn), yangzihao(yangzihao@china-icv.cn)
  10. @Data: 2023/08/21
  11. @Last Modified: 2023/08/21
  12. @Summary: Compliance metrics
  13. """
  14. import sys
  15. sys.path.append('../common')
  16. sys.path.append('../modules')
  17. sys.path.append('../results')
  18. import numpy as np
  19. import pandas as pd
  20. from data_info import DataInfoList
  21. from common import score_grade, string_concatenate, replace_key_with_value, score_over_100
  22. from scipy.spatial.distance import euclidean
  23. class Compliance(object):
  24. """
  25. Class for achieving compliance metrics for autonomous driving.
  26. Attributes:
  27. droadMark_df: Roadmark data, stored in dataframe format.
  28. """
  29. def __init__(self, data_processed, custom_data, scoreModel):
  30. self.eval_data = pd.DataFrame()
  31. self.scoreModel = scoreModel
  32. self.roadMark_df = data_processed.road_mark_df
  33. self.trafficLight_df = data_processed.traffic_light_df
  34. self.trafficSignal_df = data_processed.traffic_signal_df
  35. self.objState_df = data_processed.object_df
  36. self.violation_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'violation'])
  37. self.illegal_count = 0
  38. self.penalty_points = 0
  39. self.penalty_money = 0
  40. self.warning_count = 0
  41. self.config = data_processed.config
  42. compliance_config = self.config.config['compliance']
  43. self.compliance_config = compliance_config
  44. # common data
  45. self.bulitin_metric_list = self.config.builtinMetricList
  46. # dimension data
  47. self.weight_custom = compliance_config['weightCustom']
  48. self.metric_list = compliance_config['metric']
  49. self.type_list = compliance_config['type']
  50. self.type_name_dict = compliance_config['typeName']
  51. self.name_dict = compliance_config['name']
  52. self.unit_dict = compliance_config['unit']
  53. self.metric_dict = compliance_config['typeMetricDict']
  54. # custom metric data
  55. # self.customMetricParam = compliance_config['customMetricParam']
  56. # self.custom_metric_list = list(self.customMetricParam.keys())
  57. self.custom_data = custom_data
  58. self.custom_param_dict = {}
  59. # score data
  60. self.weight = compliance_config['weightDimension']
  61. self.weight_dict = compliance_config['weight']
  62. self.weight_list = compliance_config['weightList']
  63. self.weight_type_dict = compliance_config['typeWeight']
  64. self.weight_type_list = compliance_config['typeWeightList']
  65. # type dicts
  66. self.type_illegal_count_dict = {}
  67. self.type_penalty_points_dict = {}
  68. self.type_penalty_money_dict = {}
  69. self.type_warning_count_dict = {}
  70. self.type_penalty_law_dict = {}
  71. # metric dicts
  72. self.metric_illegal_count_dict = {}
  73. self.metric_penalty_points_dict = {}
  74. self.metric_penalty_money_dict = {}
  75. self.metric_warning_count_dict = {}
  76. self.metric_penalty_law_dict = {}
  77. # self.metric_illegal_list = []
  78. self.metric_illegal_count_list = []
  79. self.metric_penalty_points_list = []
  80. self.metric_penalty_money_list = []
  81. self.metric_warning_count_list = []
  82. self.metric_penalty_law_list = []
  83. def press_solid_line(self):
  84. """
  85. #define RDB_ROADMARK_TYPE_NONE 0
  86. #define RDB_ROADMARK_TYPE_SOLID 1
  87. #define RDB_ROADMARK_TYPE_BROKEN 2
  88. #define RDB_ROADMARK_TYPE_CURB 3
  89. #define RDB_ROADMARK_TYPE_GRASS 4
  90. #define RDB_ROADMARK_TYPE_BOTDOT 5
  91. #define RDB_ROADMARK_TYPE_OTHER 6
  92. #define RDB_ROADMARK_TYPE_SOLID_SOLID 7
  93. #define RDB_ROADMARK_TYPE_BROKEN_SOLID 8
  94. #define RDB_ROADMARK_TYPE_SOLID_BROKEN 9
  95. #define RDB_ROADMARK_TYPE_LANE_CENTER 10
  96. #define RDB_ROADMARK_COLOR_NONE 0
  97. #define RDB_ROADMARK_COLOR_WHITE 1
  98. #define RDB_ROADMARK_COLOR_RED 2
  99. #define RDB_ROADMARK_COLOR_YELLOW 3
  100. #define RDB_ROADMARK_COLOR_OTHER 4
  101. #define RDB_ROADMARK_COLOR_BLUE 5
  102. #define RDB_ROADMARK_COLOR_GREEN 6
  103. """
  104. # Dimy = self.objState_df[self.objState_df["id"] == 1]["dimY"][0] / 2
  105. Dimy = self.objState_df[self.objState_df["playerId"] == 1]["dimY"][0] / 2
  106. dist_line = self.roadMark_df[self.roadMark_df["type"] == 1]
  107. dist_line = dist_line.reset_index()
  108. dist_press = dist_line[abs(dist_line["lateralDist"].values) <= Dimy]
  109. # 违规行为详情表统计
  110. t_list = dist_press['simTime'].values.tolist()
  111. f_list = dist_press['simFrame'].values.tolist()
  112. group_time = []
  113. group_frame = []
  114. sub_group_time = []
  115. sub_group_frame = []
  116. for i in range(len(f_list)):
  117. if not sub_group_time or t_list[i] - t_list[i - 1] <= 1:
  118. sub_group_time.append(t_list[i])
  119. sub_group_frame.append(f_list[i])
  120. else:
  121. group_time.append(sub_group_time)
  122. group_frame.append(sub_group_frame)
  123. sub_group_time = [t_list[i]]
  124. sub_group_frame = [f_list[i]]
  125. CONTINUOUS_FRAME_PERIOD = 13
  126. group_time.append(sub_group_time)
  127. group_frame.append(sub_group_frame)
  128. group_time = [g for g in group_time if len(g) >= CONTINUOUS_FRAME_PERIOD]
  129. group_frame = [g for g in group_frame if len(g) >= CONTINUOUS_FRAME_PERIOD]
  130. # group_time = [g for g in group_time if g[-1]-g[0] >= 1]
  131. # group_frame = [g for g in group_frame if g[-1]-g[0] >= 13]
  132. press_line_count = len(group_time)
  133. # 输出图表值
  134. press_line_time = [[g[0], g[-1]] for g in group_time]
  135. press_line_frame = [[g[0], g[-1]] for g in group_frame]
  136. if press_line_time:
  137. time_df = pd.DataFrame(press_line_time, columns=['start_time', 'end_time'])
  138. # frame_df = pd.DataFrame(press_line_frame, columns=['start_frame', 'end_frame'])
  139. time_df['violation'] = '压实线'
  140. # frame_df['violation'] = '压实线'
  141. # self.violation_df = pd.concat([self.violation_df, time_df, frame_df], ignore_index=True)
  142. self.violation_df = pd.concat([self.violation_df, time_df], ignore_index=True)
  143. # self.violation_df = pd.concat([self.violation_df, frame_df], ignore_index=True)
  144. warning_count = 0
  145. press_line_dict = {
  146. 'metric': 'pressSolidLine',
  147. 'weight': 3,
  148. 'illegal_count': press_line_count,
  149. 'penalty_points': press_line_count * 3,
  150. 'penalty_money': press_line_count * 200,
  151. 'warning_count': warning_count,
  152. 'penalty_law': '《中华人民共和国道路交通安全法》第八十二条:机动车在高速公路上行驶,不得有下列行为:(三)骑、轧车行道分界线或者在路肩上行驶。'
  153. }
  154. return press_line_dict
  155. def normalization_processing(self, x):
  156. difference = x["traffic_light_h_diff"]
  157. while (difference >= 360):
  158. difference -= 360
  159. return difference
  160. def flag_red_traffic_light(self, x, cycleTime, duration_start, duration_end):
  161. divisor = x['simTime'] / cycleTime
  162. decimal_part = divisor - int(divisor)
  163. # decimal_part = divisor % 1
  164. if duration_start <= decimal_part < duration_end:
  165. return 1
  166. else:
  167. return x["flag_red_traffic_light"]
  168. def run_red_light(self):
  169. """
  170. """
  171. ego_df = self.objState_df[(self.objState_df.playerId == 1) & (self.objState_df.type == 1)]
  172. trafficLight_id_list = set(self.trafficLight_df["id"].tolist())
  173. l_stipulate = 10
  174. run_red_light_count = 0
  175. for trafficLight_id in trafficLight_id_list:
  176. trafficLight_position = self.trafficSignal_df[self.trafficSignal_df["playerId"] == trafficLight_id]
  177. trafficLight_character = self.trafficLight_df[self.trafficLight_df.id == trafficLight_id]
  178. if trafficLight_position.empty: # trafficSign中没有记录
  179. continue
  180. trafficLight_position = trafficLight_position.iloc[:1, :]
  181. trafficLight_position_x = trafficLight_position['posX'].values[0]
  182. trafficLight_position_y = trafficLight_position['posY'].values[0]
  183. trafficLight_position_heading = trafficLight_position['posH'].values[0]
  184. cycleTime = trafficLight_character["cycleTime"].values[0]
  185. noPhases = trafficLight_character["noPhases"].values[0]
  186. ego_df["traffic_light_distance_absolute"] = ego_df[['posX', 'posY']].apply( \
  187. lambda x: euclidean((trafficLight_position_x, trafficLight_position_y), (x['posX'], x['posY'])), axis=1)
  188. ego_df["traffic_light_h_diff"] = ego_df.apply(
  189. lambda x: abs(x['posH'] - trafficLight_position_heading) * 57.3, axis=1)
  190. ego_df["traffic_light_h_diff"] = ego_df.apply(
  191. lambda x: self.normalization_processing(x), axis=1).copy() # 归一化到[0,360)之间
  192. mask_trafftic_light = ((ego_df['traffic_light_h_diff'] <= 210) & (
  193. ego_df['traffic_light_h_diff'] >= 150)) | (ego_df['traffic_light_h_diff'] <= 30) | (
  194. ego_df['traffic_light_h_diff'] >= 330)
  195. ego_near_light = ego_df[(ego_df.traffic_light_distance_absolute <= l_stipulate) & mask_trafftic_light]
  196. if ego_near_light.empty:
  197. continue
  198. """ 当前是否为红灯 """
  199. ego_near_light["flag_red_traffic_light"] = 0 # 不是红灯
  200. type_list = trafficLight_character['violation'][:noPhases]
  201. duration = trafficLight_character['duration'][:noPhases]
  202. duration_correct = [0] * noPhases
  203. for number in range(noPhases):
  204. duration_correct[number] = sum(duration[:number + 1])
  205. type_current = type_list.values[number]
  206. if type_current == 1: # 当前duration是红灯
  207. if number == 0:
  208. duration_start = 0
  209. else:
  210. duration_start = duration_correct[number - 1]
  211. duration_end = duration_correct[number]
  212. ego_near_light["flag_red_traffic_light"] = ego_near_light[
  213. ['simTime', 'flag_red_traffic_light']].apply(
  214. lambda x: self.flag_red_traffic_light(x, cycleTime, duration_start, duration_end), axis=1)
  215. # 挑出闯红灯数据
  216. run_red_light_df = ego_near_light[ego_near_light['flag_red_traffic_light'] == 1]
  217. # 违规行为详情表统计
  218. t_list = run_red_light_df['simTime'].values.tolist()
  219. f_list = run_red_light_df['simFrame'].values.tolist()
  220. group_time = []
  221. group_frame = []
  222. sub_group_time = []
  223. sub_group_frame = []
  224. for i in range(len(f_list)):
  225. if not sub_group_time or t_list[i] - t_list[i - 1] <= 1:
  226. sub_group_time.append(t_list[i])
  227. sub_group_frame.append(f_list[i])
  228. else:
  229. group_time.append(sub_group_time)
  230. group_frame.append(sub_group_frame)
  231. sub_group_time = [t_list[i]]
  232. sub_group_frame = [f_list[i]]
  233. CONTINUOUS_FRAME_PERIOD = 13
  234. group_time.append(sub_group_time)
  235. group_frame.append(sub_group_frame)
  236. group_time = [g for g in group_time if len(g) >= CONTINUOUS_FRAME_PERIOD]
  237. group_frame = [g for g in group_frame if len(g) >= CONTINUOUS_FRAME_PERIOD]
  238. run_red_light_time = [[g[0], g[-1]] for g in group_time]
  239. run_red_light_frame = [[g[0], g[-1]] for g in group_frame]
  240. if run_red_light_time:
  241. time_df = pd.DataFrame(run_red_light_time, columns=['start_time', 'end_time'])
  242. # frame_df = pd.DataFrame(run_red_light_frame, columns=['start_frame', 'end_frame'])
  243. time_df['violation'] = '闯红灯'
  244. # frame_df['violation'] = '闯红灯'
  245. self.violation_df = pd.concat([self.violation_df, time_df], ignore_index=True)
  246. # self.violation_df = pd.concat([self.violation_df, frame_df], ignore_index=True)
  247. # 闯红灯次数统计
  248. if ego_near_light["flag_red_traffic_light"].any() == 1:
  249. run_red_light_count = run_red_light_count + 1
  250. run_red_light_dict = {
  251. 'metric': 'runRedLight',
  252. 'weight': 6,
  253. 'illegal_count': run_red_light_count,
  254. 'penalty_points': run_red_light_count * 6,
  255. 'penalty_money': run_red_light_count * 200,
  256. 'warning_count': 0,
  257. 'penalty_law': '《中华人民共和国道路交通安全法实施条例》第四十条:(二)红色叉形灯或者箭头灯亮时,禁止本车道车辆通行。'
  258. }
  259. return run_red_light_dict
  260. def overspeed(self):
  261. """
  262. 《中华人民共和国道路交通安全法实施条例》第四十五条:机动车在道路上行驶不得超过限速标志、标线标明的速度;
  263. 1、高速、城市快速路超速超过规定时速10%以内,处以警告,不扣分;
  264. 2、普通私家车高速超过规定时速10%以上未达20%的,处以200元罚款,记3分,普通私家车在除高速公路、城市快速路外的道路,超速20%以上未达到50%,会一次被记3分;
  265. 3、超过规定时速20%以上未达50%的,处以200元罚款,记6分,或在普通道路上超速50%以上,都会一次被记6分。;
  266. 4、超过规定时速50%以上的,可吊销驾驶证并罚款2000元,计12分。
  267. [0, 10) 0,0,1
  268. [10, 20) 0,200,1
  269. 高速、城市快速路:[20, 50) 6,200
  270. 高速、城市快速路:[50,)12,2000
  271. 高速、城市以外:[20, 50)3,200
  272. 高速、城市以外:[50,)6,1000-2000
  273. """
  274. Dimx = self.objState_df[self.objState_df["playerId"] == 1]["dimX"][0] / 2
  275. data_ego = self.objState_df[self.objState_df["playerId"] == 1]
  276. speed_limit_sign = self.trafficSignal_df[self.trafficSignal_df["type"] == 274]
  277. same_df_rate = pd.merge(speed_limit_sign, data_ego, on=['simTime', 'simFrame'], how='inner')
  278. same_df_rate = same_df_rate.reset_index()
  279. speed_df = same_df_rate[(abs(same_df_rate["posX_x"] - same_df_rate["posX_y"]) <= 7) & (
  280. abs(same_df_rate["posY_x"] - same_df_rate["posY_y"]) <= Dimx)]
  281. speed_df["speed"] = np.sqrt(speed_df["speedX"] ** 2 + speed_df["speedY"] ** 2) * 3.6
  282. # speed_df["value"] = 10
  283. # same_df_rate["value"] = 10
  284. list_sign = speed_df[speed_df["speed"] > speed_df["value"]]
  285. # 违规行为详情表统计
  286. t_list = list_sign['simTime'].values.tolist()
  287. f_list = list_sign['simFrame'].values.tolist()
  288. group_time = []
  289. group_frame = []
  290. sub_group_time = []
  291. sub_group_frame = []
  292. for i in range(len(f_list)):
  293. if not sub_group_time or t_list[i] - t_list[i - 1] <= 2:
  294. sub_group_time.append(t_list[i])
  295. sub_group_frame.append(f_list[i])
  296. else:
  297. group_time.append(sub_group_time)
  298. group_frame.append(sub_group_frame)
  299. sub_group_time = [t_list[i]]
  300. sub_group_frame = [f_list[i]]
  301. CONTINUOUS_FRAME_PERIOD = 13
  302. group_time.append(sub_group_time)
  303. group_frame.append(sub_group_frame)
  304. group_time = [g for g in group_time if len(g) >= CONTINUOUS_FRAME_PERIOD]
  305. group_frame = [g for g in group_frame if len(g) >= CONTINUOUS_FRAME_PERIOD]
  306. # 输出图表值
  307. overspeed_time = [[g[0], g[-1]] for g in group_time]
  308. overspeed_frame = [[g[0], g[-1]] for g in group_frame]
  309. if overspeed_time:
  310. time_df = pd.DataFrame(overspeed_time, columns=['start_time', 'end_time'])
  311. # frame_df = pd.DataFrame(overspeed_frame, columns=['start_frame', 'end_frame'])
  312. time_df['violation'] = '超速'
  313. # frame_df['violation'] = '超速'
  314. self.violation_df = pd.concat([self.violation_df, time_df], ignore_index=True)
  315. # self.violation_df = pd.concat([self.violation_df, frame_df], ignore_index=True)
  316. # list_sign = list_sign.reset_index()
  317. index_sign = list_sign.index.to_list()
  318. speed_df["flag_press"] = speed_df["simFrame"].apply(lambda x: 1 if x in list_sign["simFrame"] else 0)
  319. speed_df["diff_press"] = speed_df["flag_press"].diff()
  320. # overrate_count = speed_df[speed_df["diff_press"] == -1]["diff_press"].count()
  321. index_list = []
  322. subindex_list = []
  323. for i in range(len(index_sign)):
  324. if not subindex_list or index_sign[i] - index_sign[i - 1] == 1:
  325. subindex_list.append(index_sign[i])
  326. else:
  327. index_list.append(subindex_list)
  328. subindex_list.append(index_sign[i])
  329. index_list.append(subindex_list)
  330. overspeed_count_0_to_10 = 0
  331. overspeed_count_10_to_20 = 0
  332. overspeed_count_20_to_50 = 0
  333. overspeed_count_50_to_ = 0
  334. if index_list[0]:
  335. for i in range(len(index_list)):
  336. left = index_list[i][0]
  337. right = index_list[i][-1]
  338. df_tmp = speed_df.loc[left:right + 1]
  339. max_ratio = ((df_tmp["speed"] - df_tmp["value"]) / df_tmp["value"]).max()
  340. if max_ratio >= 0 and max_ratio < 0.1:
  341. overspeed_count_0_to_10 += 1
  342. elif max_ratio >= 0.1 and max_ratio < 0.2:
  343. overspeed_count_10_to_20 += 1
  344. elif max_ratio >= 0.2 and max_ratio < 0.5:
  345. overspeed_count_20_to_50 += 1
  346. elif max_ratio >= 0.5:
  347. overspeed_count_50_to_ += 1
  348. """
  349. [0, 10) 0,0,1
  350. [10, 20) 0,200,1
  351. 高速、城市快速路:[20, 50) 6,200
  352. 高速、城市快速路:[50,)12,2000
  353. """
  354. overspeed_0_to_10 = {
  355. # 'metric': 'overspeed_0_to_10',
  356. 'metric': 'overspeed10',
  357. 'weight': None,
  358. 'illegal_count': overspeed_count_0_to_10,
  359. 'penalty_points': 0,
  360. 'penalty_money': 0,
  361. 'warning_count': overspeed_count_0_to_10,
  362. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  363. }
  364. overspeed_10_to_20 = {
  365. # 'metric': 'overspeed_10_to_20',
  366. 'metric': 'overspeed10_20',
  367. 'weight': None,
  368. 'illegal_count': overspeed_count_10_to_20,
  369. 'penalty_points': 0,
  370. 'penalty_money': overspeed_count_10_to_20 * 200,
  371. 'warning_count': overspeed_count_10_to_20,
  372. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  373. }
  374. overspeed_20_to_50 = {
  375. # 'metric': 'overspeed_20_to_50',
  376. 'metric': 'overspeed20_50',
  377. 'weight': 6,
  378. 'illegal_count': overspeed_count_20_to_50,
  379. 'penalty_points': overspeed_count_20_to_50 * 6,
  380. 'penalty_money': overspeed_count_20_to_50 * 200,
  381. 'warning_count': 0,
  382. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  383. }
  384. overspeed_50_to_ = {
  385. # 'metric': 'overspeed_50_to_',
  386. 'metric': 'overspeed50',
  387. 'weight': 12,
  388. 'illegal_count': overspeed_count_50_to_,
  389. 'penalty_points': overspeed_count_50_to_ * 12,
  390. 'penalty_money': overspeed_count_50_to_ * 2000,
  391. 'warning_count': 0,
  392. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  393. }
  394. return overspeed_0_to_10, overspeed_10_to_20, overspeed_20_to_50, overspeed_50_to_
  395. def score_cal_penalty_points(self, penalty_points):
  396. """
  397. # 1_results: 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 100
  398. # 3_results: 0, 15, 30, 45, 100
  399. # 6_results: 0, 30, 100
  400. # 9_results: 0, 15, 100
  401. """
  402. if penalty_points == 0:
  403. score = 100
  404. elif penalty_points >= 12:
  405. score = 0
  406. else:
  407. score = (12 - penalty_points) / 12 * 60
  408. return score
  409. def time_splice(self, start_time, end_time):
  410. str_time = f"[{start_time}s, {end_time}s]"
  411. return str_time
  412. def time_frame_splice(self, start_time, end_time, start_frame, end_frame):
  413. str_time = f"[{start_time}s, {end_time}s], {start_frame}-{end_frame}"
  414. return str_time
  415. def weight_type_cal(self):
  416. # penalty_list = [1, 3, 6, 9, 12]
  417. penalty_list = [1, 3, 6, 12]
  418. sum_penalty = sum(penalty_list)
  419. weight_type_list = [round(x / sum_penalty, 2) for x in penalty_list]
  420. return weight_type_list
  421. def compliance_statistic(self):
  422. # metric analysis
  423. press_line_dict = self.press_solid_line()
  424. run_red_light_dict = self.run_red_light()
  425. overspeed_0_to_10_dict, overspeed_10_to_20_dict, overspeed_20_to_50_dict, overspeed_50_dict = self.overspeed()
  426. df_list = []
  427. if "overspeed10" in self.metric_list:
  428. df_list.append(overspeed_0_to_10_dict)
  429. if "overspeed10_20" in self.metric_list:
  430. df_list.append(overspeed_10_to_20_dict)
  431. if "pressSolidLine" in self.metric_list:
  432. df_list.append(press_line_dict)
  433. if "runRedLight" in self.metric_list:
  434. df_list.append(run_red_light_dict)
  435. if "overspeed20_50" in self.metric_list:
  436. df_list.append(overspeed_20_to_50_dict)
  437. if "overspeed50" in self.metric_list:
  438. df_list.append(overspeed_50_dict)
  439. # generate dataframe and dicts
  440. compliance_df = pd.DataFrame(df_list)
  441. return compliance_df
  442. def compliance_score(self):
  443. """
  444. 待优化
  445. 可以重新构建数据结构,每个判断函数的返回类型为dict
  446. 在多指标统计扣分、罚款时,可以将所有字典合并为一个dataframe,然后求和
  447. """
  448. # initialization
  449. score_type_dict = {}
  450. compliance_df = self.compliance_statistic()
  451. self.illegal_count = int(compliance_df['illegal_count'].sum())
  452. # self.penalty_points = compliance_df['penalty_points'].sum()
  453. # self.penalty_money = compliance_df['penalty_money'].sum()
  454. # self.warning_count = compliance_df['warning_count'].sum()
  455. # self.metric_illegal_list = compliance_df[compliance_df['illegal_count'] > 0]['metric'].tolist()
  456. # self.metric_illegal_count_list = compliance_df['illegal_count'].values.tolist()
  457. #
  458. # self.penalty_points_list = compliance_df['penalty_points'].values.tolist()
  459. # self.penalty_money_list = compliance_df['penalty_money'].values.tolist()
  460. # self.warning_count_list = compliance_df['warning_count'].values.tolist()
  461. self.metric_penalty_points_dict = compliance_df.set_index('metric').to_dict()['penalty_points']
  462. self.metric_illegal_count_dict = compliance_df.set_index('metric').to_dict()['illegal_count']
  463. self.metric_penalty_money_dict = compliance_df.set_index('metric').to_dict()['penalty_money']
  464. self.metric_warning_count_dict = compliance_df.set_index('metric').to_dict()['warning_count']
  465. self.metric_penalty_law_dict = compliance_df.set_index('metric').to_dict()['penalty_law']
  466. # deduct1
  467. if "deduct1" in self.type_list:
  468. deduct1_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 1)]
  469. penalty_points_1 = deduct1_df['penalty_points'].sum()
  470. illegal_count_1 = deduct1_df['illegal_count'].sum()
  471. score_type_dict["deduct1"] = self.score_cal_penalty_points(penalty_points_1)
  472. self.type_illegal_count_dict["deduct1"] = illegal_count_1
  473. # deduct3
  474. if "deduct3" in self.type_list:
  475. deduct3_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 3)]
  476. penalty_points_3 = deduct3_df['penalty_points'].sum()
  477. illegal_count_3 = deduct3_df['illegal_count'].sum()
  478. score_type_dict["deduct3"] = self.score_cal_penalty_points(penalty_points_3)
  479. self.type_illegal_count_dict["deduct3"] = illegal_count_3
  480. # deduct6
  481. if "deduct6" in self.type_list:
  482. deduct6_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 6)]
  483. penalty_points_6 = deduct6_df['penalty_points'].sum()
  484. illegal_count_6 = deduct6_df['illegal_count'].sum()
  485. score_type_dict["deduct6"] = self.score_cal_penalty_points(penalty_points_6)
  486. self.type_illegal_count_dict["deduct6"] = illegal_count_6
  487. # deduct9
  488. if "deduct9" in self.type_list:
  489. deduct9_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 9)]
  490. penalty_points_9 = deduct9_df['penalty_points'].sum()
  491. illegal_count_9 = deduct9_df['illegal_count'].sum()
  492. score_type_dict["deduct9"] = self.score_cal_penalty_points(penalty_points_9)
  493. self.type_illegal_count_dict["deduct9"] = illegal_count_9
  494. # deduct12
  495. if "deduct12" in self.type_list:
  496. deduct12_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 12)]
  497. penalty_points_12 = deduct12_df['penalty_points'].sum()
  498. illegal_count_12 = deduct12_df['illegal_count'].sum()
  499. score_type_dict["deduct12"] = self.score_cal_penalty_points(penalty_points_12)
  500. self.type_illegal_count_dict["deduct12"] = illegal_count_12
  501. weight_type_list = self.weight_type_cal()
  502. weight_dict = {
  503. "overspeed10": 0.5,
  504. "overspeed10_20": 0.5,
  505. "pressSolidLine": 1.0,
  506. "runRedLight": 0.5,
  507. "overspeed20_50": 0.5,
  508. "overspeed50": 1.0
  509. }
  510. type_list = ["deduct1", "deduct3", "deduct6", "deduct12"]
  511. if not self.weight_custom: # 客观赋权
  512. self.weight_type_list = weight_type_list
  513. self.weight_type_dict = {key: value for key, value in zip(type_list, weight_type_list)}
  514. self.weight_dict = weight_dict
  515. if self.penalty_points >= 12:
  516. score_compliance = 0
  517. elif sum(score_type_dict.values()) / len(score_type_dict) == 100:
  518. score_compliance = 100
  519. else:
  520. score_type_tmp = [80 if x == 100 else x for key, x in score_type_dict.items()]
  521. score_compliance = np.dot(self.weight_type_list, score_type_tmp)
  522. score_compliance = round(score_compliance, 2)
  523. print("\n[合规性表现及得分情况]")
  524. print(f"合规性得分为:{score_compliance:.2f}分。")
  525. print(f"合规性各分组得分为:{score_type_dict}。")
  526. print(f"合规性各分组权重为:{self.weight_type_list}。")
  527. # print(f"合规性各指标违规次数为:\n{count_metric}。")
  528. # print(f"违法总次数为:{self.illegal_count}。")
  529. # print(f"违法扣分总数为:{self.penalty_points}。")
  530. # print(f"罚款总金额为:{self.penalty_money}。")
  531. # print(f"警告总次数为:{self.warning_count}。")
  532. # print(compliance_df)
  533. return score_compliance, score_type_dict
  534. def _get_weight_distribution(self):
  535. # get weight distribution
  536. weight_distribution = {}
  537. weight_distribution["name"] = self.config.dimension_name["compliance"]
  538. for type in self.type_list:
  539. type_weight_indexes_dict = {key: f"{self.name_dict[key]}({value * 100:.2f}%)" for key, value in
  540. self.weight_dict.items() if
  541. key in self.metric_dict[type]}
  542. weight_distribution_type = {
  543. "weight": f"{self.type_name_dict[type]}({self.weight_type_dict[type] * 100:.2f}%)",
  544. "indexes": type_weight_indexes_dict
  545. }
  546. weight_distribution[type] = weight_distribution_type
  547. return weight_distribution
  548. def compliance_weight_distribution(self):
  549. # get weight distribution
  550. weight_distribution = {}
  551. weight_distribution["name"] = "合规性"
  552. if "deduct1" in self.type_list:
  553. deduct1_weight_indexes_dict = {}
  554. if "overspeed10" in self.metric_list:
  555. deduct1_weight_indexes_dict[
  556. "overspeed10Weight"] = f"超速,但未超过10%({self.weight_dict['overspeed10'] * 100:.2f}%)"
  557. if "overspeed10_20" in self.metric_list:
  558. deduct1_weight_indexes_dict[
  559. "overspeed1020Weight"] = f"超速10%-20%({self.weight_dict['overspeed10_20'] * 100:.2f}%)"
  560. weight_distribution['deduct1'] = {
  561. "deduct1Weight": f"轻微违规(1分)({self.weight_type_dict['deduct1'] * 100:.2f}%)",
  562. "indexes": deduct1_weight_indexes_dict
  563. }
  564. if "deduct3" in self.type_list:
  565. deduct3_weight_indexes_dict = {}
  566. if "pressSolidLine" in self.metric_list:
  567. deduct3_weight_indexes_dict[
  568. "pressSolidLineWeight"] = f"压实线({self.weight_dict['pressSolidLine'] * 100:.2f}%)"
  569. weight_distribution['deduct3'] = {
  570. "deduct3Weight": f"中等违规(3分)({self.weight_type_dict['deduct3'] * 100:.2f}%)",
  571. "indexes": deduct3_weight_indexes_dict
  572. }
  573. if "deduct6" in self.type_list:
  574. deduct6_weight_indexes_dict = {}
  575. if "runRedLight" in self.metric_list:
  576. deduct6_weight_indexes_dict["runRedLightWeight"] = f"闯红灯({self.weight_dict['runRedLight'] * 100:.2f}%)"
  577. if "overspeed20_50" in self.metric_list:
  578. deduct6_weight_indexes_dict[
  579. "overspeed2050Weight"] = f"超速20%-50%({self.weight_dict['overspeed20_50'] * 100:.2f}%)"
  580. weight_distribution['deduct6'] = {
  581. "deduct6Weight": f"危险违规(6分)({self.weight_type_dict['deduct6'] * 100:.2f}%)",
  582. "indexes": deduct6_weight_indexes_dict
  583. }
  584. if "deduct9" in self.type_list:
  585. deduct9_weight_indexes_dict = {}
  586. weight_distribution['deduct9'] = {
  587. "deduct9Weight": f"严重违规(9分)({self.weight_type_dict['deduct6'] * 100:.2f}%)",
  588. "indexes": deduct9_weight_indexes_dict
  589. }
  590. if "deduct12" in self.type_list:
  591. deduct12_weight_indexes_dict = {}
  592. if "overspeed50" in self.metric_list:
  593. deduct12_weight_indexes_dict[
  594. "overspeed50Weight"] = f"超速50%以上({self.weight_dict['overspeed50'] * 100:.2f}%)"
  595. weight_distribution['deduct12'] = {
  596. "deduct12Weight": f"重大违规(12分)({self.weight_type_dict['deduct12'] * 100:.2f}%)",
  597. "indexes": deduct12_weight_indexes_dict
  598. }
  599. return weight_distribution
  600. def report_statistic(self):
  601. score_compliance, score_type_dict = self.compliance_score()
  602. grade_compliance = score_grade(score_compliance)
  603. score_compliance = int(score_compliance) if int(score_compliance) == score_compliance else score_compliance
  604. score_type = [int(n) if int(n) == n else n for key, n in score_type_dict.items()]
  605. # get weight distribution
  606. # weight_distribution = self.compliance_weight_distribution()
  607. weight_distribution = self._get_weight_distribution()
  608. # if self.metric_illegal_list:
  609. # str_illegel_metric = string_concatenate(self.metric_illegal_list)
  610. cnt1 = self.illegal_count
  611. if grade_compliance == '优秀':
  612. comp_description1 = '车辆在本轮测试中无违反交通法规行为;'
  613. elif grade_compliance == '良好':
  614. comp_description1 = f'车辆在本轮测试中共发生{cnt1}次违反交通法规⾏为;'
  615. elif grade_compliance == '一般':
  616. comp_description1 = f'车辆在本轮测试中共有{cnt1}次违反交通法规⾏为,需要提高算法在合规性上的表现;'
  617. elif grade_compliance == '较差':
  618. comp_description1 = f'车辆在本轮测试中共有{cnt1}次违反交通法规⾏为,需要提高算法在合规性上的表现;'
  619. # xx指标得分超过基准线且无违规行为,算法表现良好
  620. # 违规次数 self.illegal_count
  621. # 1分xx次,3分xx次
  622. if cnt1 == 0:
  623. comp_description2 = "车辆在该用例中无违反交通法规行为,算法表现良好。"
  624. else:
  625. str_illegel_type = ""
  626. for type in self.type_list:
  627. if self.type_illegal_count_dict[type] > 0:
  628. str_illegel_type += f'{self.type_name_dict[type]}行为{self.type_illegal_count_dict[type]}次,'
  629. # if "deduct1" in self.type_list:
  630. # if self.type_illegal_count_dict["deduct1"] > 0:
  631. # str_illegel_type += f'轻微违规(1分)行为{self.type_illegal_count_dict["deduct1"]}次,'
  632. #
  633. # if "deduct3" in self.type_list:
  634. # if self.type_illegal_count_dict["deduct3"] > 0:
  635. # str_illegel_type += f'中等违规(3分)行为{self.type_illegal_count_dict["deduct3"]}次,'
  636. #
  637. # if "deduct6" in self.type_list:
  638. # if self.type_illegal_count_dict["deduct6"] > 0:
  639. # str_illegel_type += f'危险违规(6分)行为{self.type_illegal_count_dict["deduct6"]}次,'
  640. #
  641. # if "deduct9" in self.type_list:
  642. # if self.type_illegal_count_dict["deduct9"] > 0:
  643. # str_illegel_type += f'严重违规(9分)行为{self.type_illegal_count_dict["deduct9"]}次,'
  644. #
  645. # if "deduct12" in self.type_list:
  646. # if self.type_illegal_count_dict["deduct12"] > 0:
  647. # str_illegel_type += f'重大违规(12分)行为{self.type_illegal_count_dict["deduct12"]}次,'
  648. str_illegel_type = str_illegel_type[:-1]
  649. comp_description2 = f"车辆在该用例共违反交通法规{cnt1}次。其中{str_illegel_type}。违规行为详情见附录C。"
  650. # data for violations table
  651. if not self.violation_df.empty:
  652. # self.violation_df['time'] = self.violation_df.apply(
  653. # lambda row: self.time_frame_splice(row['start_time'], row['end_time'], row['start_frame'],
  654. # row['end_frame']), axis=1)
  655. self.violation_df['time'] = self.violation_df.apply(
  656. lambda row: self.time_splice(row['start_time'], row['end_time']), axis=1)
  657. df_violations = self.violation_df[['time', 'violation']]
  658. violations_slices = df_violations.to_dict('records')
  659. else:
  660. violations_slices = []
  661. # violations_slices = [{'time': "[1s, 2s]", 'violation': "压实线"},
  662. # {'time': "[10s, 20s]", 'violation': "闯红灯"},
  663. # {'time': "[100s, 200s]", 'violation': "超速"}]
  664. deductPoint_dict = {}
  665. for type in self.type_list:
  666. type_dict = {
  667. "name": self.type_name_dict[type],
  668. "score": score_type_dict[type],
  669. }
  670. type_indexes = {}
  671. for metric in self.metric_list:
  672. type_indexes[metric] = {
  673. # "name": self.name_dict[metric],
  674. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  675. "name": f"{self.name_dict[metric]}",
  676. "times": self.metric_illegal_count_dict[metric],
  677. "deductPoints": self.metric_penalty_points_dict[metric],
  678. "fine": self.metric_penalty_money_dict[metric],
  679. "basis": self.metric_penalty_law_dict[metric]
  680. }
  681. type_dict["indexes"] = type_indexes
  682. deductPoint_dict[type] = type_dict
  683. # deduct1
  684. if "deduct1" in self.type_list:
  685. deduct1_indexes = {}
  686. if "overspeed10" in self.metric_list:
  687. tmp_dict = {
  688. "name": "超速,但未超过10%",
  689. "times": self.metric_illegal_count_dict["overspeed10"],
  690. "deductPoints": self.metric_penalty_points_dict["overspeed10"],
  691. "fine": self.metric_penalty_money_dict["overspeed10"],
  692. "basis": self.metric_penalty_law_dict["overspeed10"]
  693. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  694. }
  695. deduct1_indexes['overspeed10'] = tmp_dict
  696. if "overspeed10_20" in self.metric_list:
  697. tmp_dict = {
  698. "name": "超速10%-20%",
  699. "times": self.metric_illegal_count_dict["overspeed10_20"],
  700. "deductPoints": self.metric_penalty_points_dict["overspeed10_20"],
  701. "fine": self.metric_penalty_money_dict["overspeed10_20"],
  702. "basis": self.metric_penalty_law_dict["overspeed10_20"]
  703. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  704. }
  705. deduct1_indexes['overspeed10_20'] = tmp_dict
  706. deduct1_dict = {
  707. "name": "轻微违规(1分)",
  708. "score": score_type_dict["deduct1"],
  709. "indexes": deduct1_indexes
  710. }
  711. deductPoint_dict["deduct1"] = deduct1_dict
  712. # deduct3
  713. if "deduct3" in self.type_list:
  714. deduct3_indexes = {}
  715. if "pressSolidLine" in self.metric_list:
  716. tmp_dict = {
  717. "name": "压实线",
  718. "times": self.metric_illegal_count_dict["pressSolidLine"],
  719. "deductPoints": self.metric_penalty_points_dict["pressSolidLine"],
  720. "fine": self.metric_penalty_money_dict["pressSolidLine"],
  721. "basis": self.metric_penalty_law_dict["pressSolidLine"]
  722. # "basis": "《中华人民共和国道路交通安全法》第八十二条:机动车在高速公路上行驶,不得有下列行为:(三)骑、轧车行道分界线或者在路肩上行驶。"
  723. }
  724. deduct3_indexes['pressSolidLine'] = tmp_dict
  725. deduct3_dict = {
  726. "name": "中等违规(3分)",
  727. "score": score_type_dict["deduct3"],
  728. "indexes": deduct3_indexes
  729. }
  730. deductPoint_dict["deduct3"] = deduct3_dict
  731. # deduct6
  732. if "deduct6" in self.type_list:
  733. deduct6_indexes = {}
  734. if "runRedLight" in self.metric_list:
  735. tmp_dict = {
  736. "name": "闯红灯",
  737. "times": self.metric_illegal_count_dict["runRedLight"],
  738. "deductPoints": self.metric_penalty_points_dict["runRedLight"],
  739. "fine": self.metric_penalty_money_dict["runRedLight"],
  740. "basis": self.metric_penalty_law_dict["runRedLight"]
  741. # "basis": "《中华人民共和国道路交通安全法实施条例》第四十条:(二)红色叉形灯或者箭头灯亮时,禁止本车道车辆通行。"
  742. }
  743. deduct6_indexes['runRedLight'] = tmp_dict
  744. if "overspeed20_50" in self.metric_list:
  745. tmp_dict = {
  746. "name": "超速20%-50%",
  747. "times": self.metric_illegal_count_dict["overspeed20_50"],
  748. "deductPoints": self.metric_penalty_points_dict["overspeed20_50"],
  749. "fine": self.metric_penalty_money_dict["overspeed20_50"],
  750. "basis": self.metric_penalty_law_dict["overspeed20_50"]
  751. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  752. }
  753. deduct6_indexes['overspeed20_50'] = tmp_dict
  754. deduct6_dict = {
  755. "name": "危险违规(6分)",
  756. "score": score_type_dict["deduct6"],
  757. "indexes": deduct6_indexes
  758. }
  759. deductPoint_dict["deduct6"] = deduct6_dict
  760. # deduct9
  761. if "deduct9" in self.type_list:
  762. deduct9_indexes = {}
  763. if "xx" in self.metric_list:
  764. tmp_dict = {
  765. "name": "-",
  766. "times": "0",
  767. "deductPoints": "0",
  768. "fine": "0",
  769. "basis": "-"
  770. # "basis": "-"
  771. }
  772. deduct9_indexes['xx'] = tmp_dict
  773. deduct9_dict = {
  774. "name": "严重违规(9分)",
  775. "score": 100, # score_type_dict["deduct9"],
  776. "indexes": deduct9_indexes
  777. }
  778. deductPoint_dict["deduct9"] = deduct9_dict
  779. # deduct12
  780. if "deduct12" in self.type_list:
  781. deduct12_indexes = {}
  782. if "overspeed50" in self.metric_list:
  783. tmp_dict = {
  784. "name": "超速50%以上",
  785. "times": self.metric_illegal_count_dict["overspeed50"],
  786. "deductPoints": self.metric_penalty_points_dict["overspeed50"],
  787. "fine": self.metric_penalty_money_dict["overspeed50"],
  788. "basis": self.metric_penalty_law_dict["overspeed50"]
  789. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  790. }
  791. deduct12_indexes['overspeed50'] = tmp_dict
  792. deduct12_dict = {
  793. "name": "重大违规(12分)",
  794. "score": score_type_dict["deduct12"],
  795. "indexes": deduct12_indexes
  796. }
  797. deductPoint_dict["deduct12"] = deduct12_dict
  798. report_dict = {
  799. "name": "合规性",
  800. "weight": f"{self.weight * 100:.2f}%",
  801. "weightDistribution": weight_distribution,
  802. "score": score_compliance,
  803. "level": grade_compliance,
  804. 'score_type': score_type,
  805. # 'score_metric': score_metric,
  806. 'illegalCount': self.illegal_count,
  807. "description1": comp_description1,
  808. "description2": comp_description2,
  809. "details": deductPoint_dict,
  810. "violations": violations_slices
  811. }
  812. return report_dict
  813. def get_eval_data(self):
  814. df = self.eval_data
  815. return df