compliance.py 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  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_distance_absolute"] = ego_df.apply(lambda x: euclidean((trafficLight_position_x, trafficLight_position_y), (x['posX'], x['posY'])), axis=1)
  189. ego_df["traffic_light_h_diff"] = ego_df.apply(
  190. lambda x: abs(x['posH'] - trafficLight_position_heading) * 57.3, axis=1)
  191. ego_df["traffic_light_h_diff"] = ego_df.apply(
  192. lambda x: self.normalization_processing(x), axis=1).copy() # 归一化到[0,360)之间
  193. mask_trafftic_light = ((ego_df['traffic_light_h_diff'] <= 210) & (
  194. ego_df['traffic_light_h_diff'] >= 150)) | (ego_df['traffic_light_h_diff'] <= 30) | (
  195. ego_df['traffic_light_h_diff'] >= 330)
  196. ego_near_light = ego_df[(ego_df.traffic_light_distance_absolute <= l_stipulate) & mask_trafftic_light]
  197. if ego_near_light.empty:
  198. continue
  199. """ 当前是否为红灯 """
  200. ego_near_light["flag_red_traffic_light"] = 0 # 不是红灯
  201. type_list = trafficLight_character['violation'][:noPhases]
  202. duration = trafficLight_character['duration'][:noPhases]
  203. duration_correct = [0] * noPhases
  204. for number in range(noPhases):
  205. duration_correct[number] = sum(duration[:number + 1])
  206. type_current = type_list.values[number]
  207. if type_current == 1: # 当前duration是红灯
  208. if number == 0:
  209. duration_start = 0
  210. else:
  211. duration_start = duration_correct[number - 1]
  212. duration_end = duration_correct[number]
  213. ego_near_light["flag_red_traffic_light"] = ego_near_light[
  214. ['simTime', 'flag_red_traffic_light']].apply(
  215. lambda x: self.flag_red_traffic_light(x, cycleTime, duration_start, duration_end), axis=1)
  216. # 挑出闯红灯数据
  217. run_red_light_df = ego_near_light[ego_near_light['flag_red_traffic_light'] == 1]
  218. # 违规行为详情表统计
  219. t_list = run_red_light_df['simTime'].values.tolist()
  220. f_list = run_red_light_df['simFrame'].values.tolist()
  221. group_time = []
  222. group_frame = []
  223. sub_group_time = []
  224. sub_group_frame = []
  225. for i in range(len(f_list)):
  226. if not sub_group_time or t_list[i] - t_list[i - 1] <= 1:
  227. sub_group_time.append(t_list[i])
  228. sub_group_frame.append(f_list[i])
  229. else:
  230. group_time.append(sub_group_time)
  231. group_frame.append(sub_group_frame)
  232. sub_group_time = [t_list[i]]
  233. sub_group_frame = [f_list[i]]
  234. CONTINUOUS_FRAME_PERIOD = 13
  235. group_time.append(sub_group_time)
  236. group_frame.append(sub_group_frame)
  237. group_time = [g for g in group_time if len(g) >= CONTINUOUS_FRAME_PERIOD]
  238. group_frame = [g for g in group_frame if len(g) >= CONTINUOUS_FRAME_PERIOD]
  239. run_red_light_time = [[g[0], g[-1]] for g in group_time]
  240. run_red_light_frame = [[g[0], g[-1]] for g in group_frame]
  241. if run_red_light_time:
  242. time_df = pd.DataFrame(run_red_light_time, columns=['start_time', 'end_time'])
  243. # frame_df = pd.DataFrame(run_red_light_frame, columns=['start_frame', 'end_frame'])
  244. time_df['violation'] = '闯红灯'
  245. # frame_df['violation'] = '闯红灯'
  246. self.violation_df = pd.concat([self.violation_df, time_df], ignore_index=True)
  247. # self.violation_df = pd.concat([self.violation_df, frame_df], ignore_index=True)
  248. # 闯红灯次数统计
  249. if ego_near_light["flag_red_traffic_light"].any() == 1:
  250. run_red_light_count = run_red_light_count + 1
  251. run_red_light_dict = {
  252. 'metric': 'runRedLight',
  253. 'weight': 6,
  254. 'illegal_count': run_red_light_count,
  255. 'penalty_points': run_red_light_count * 6,
  256. 'penalty_money': run_red_light_count * 200,
  257. 'warning_count': 0,
  258. 'penalty_law': '《中华人民共和国道路交通安全法实施条例》第四十条:(二)红色叉形灯或者箭头灯亮时,禁止本车道车辆通行。'
  259. }
  260. return run_red_light_dict
  261. def overspeed(self):
  262. """
  263. 《中华人民共和国道路交通安全法实施条例》第四十五条:机动车在道路上行驶不得超过限速标志、标线标明的速度;
  264. 1、高速、城市快速路超速超过规定时速10%以内,处以警告,不扣分;
  265. 2、普通私家车高速超过规定时速10%以上未达20%的,处以200元罚款,记3分,普通私家车在除高速公路、城市快速路外的道路,超速20%以上未达到50%,会一次被记3分;
  266. 3、超过规定时速20%以上未达50%的,处以200元罚款,记6分,或在普通道路上超速50%以上,都会一次被记6分。;
  267. 4、超过规定时速50%以上的,可吊销驾驶证并罚款2000元,计12分。
  268. [0, 10) 0,0,1
  269. [10, 20) 0,200,1
  270. 高速、城市快速路:[20, 50) 6,200
  271. 高速、城市快速路:[50,)12,2000
  272. 高速、城市以外:[20, 50)3,200
  273. 高速、城市以外:[50,)6,1000-2000
  274. """
  275. Dimx = self.objState_df[self.objState_df["playerId"] == 1]["dimX"][0] / 2
  276. data_ego = self.objState_df[self.objState_df["playerId"] == 1]
  277. speed_limit_sign = self.trafficSignal_df[self.trafficSignal_df["type"] == 274]
  278. same_df_rate = pd.merge(speed_limit_sign, data_ego, on=['simTime', 'simFrame'], how='inner')
  279. same_df_rate = same_df_rate.reset_index()
  280. speed_df = same_df_rate[(abs(same_df_rate["posX_x"] - same_df_rate["posX_y"]) <= 7) & (
  281. abs(same_df_rate["posY_x"] - same_df_rate["posY_y"]) <= Dimx)]
  282. speed_df["speed"] = np.sqrt(speed_df["speedX"] ** 2 + speed_df["speedY"] ** 2) * 3.6
  283. # speed_df["value"] = 10
  284. # same_df_rate["value"] = 10
  285. list_sign = speed_df[speed_df["speed"] > speed_df["value"]]
  286. # 违规行为详情表统计
  287. t_list = list_sign['simTime'].values.tolist()
  288. f_list = list_sign['simFrame'].values.tolist()
  289. group_time = []
  290. group_frame = []
  291. sub_group_time = []
  292. sub_group_frame = []
  293. for i in range(len(f_list)):
  294. if not sub_group_time or t_list[i] - t_list[i - 1] <= 2:
  295. sub_group_time.append(t_list[i])
  296. sub_group_frame.append(f_list[i])
  297. else:
  298. group_time.append(sub_group_time)
  299. group_frame.append(sub_group_frame)
  300. sub_group_time = [t_list[i]]
  301. sub_group_frame = [f_list[i]]
  302. CONTINUOUS_FRAME_PERIOD = 13
  303. group_time.append(sub_group_time)
  304. group_frame.append(sub_group_frame)
  305. group_time = [g for g in group_time if len(g) >= CONTINUOUS_FRAME_PERIOD]
  306. group_frame = [g for g in group_frame if len(g) >= CONTINUOUS_FRAME_PERIOD]
  307. # 输出图表值
  308. overspeed_time = [[g[0], g[-1]] for g in group_time]
  309. overspeed_frame = [[g[0], g[-1]] for g in group_frame]
  310. if overspeed_time:
  311. time_df = pd.DataFrame(overspeed_time, columns=['start_time', 'end_time'])
  312. # frame_df = pd.DataFrame(overspeed_frame, columns=['start_frame', 'end_frame'])
  313. time_df['violation'] = '超速'
  314. # frame_df['violation'] = '超速'
  315. self.violation_df = pd.concat([self.violation_df, time_df], ignore_index=True)
  316. # self.violation_df = pd.concat([self.violation_df, frame_df], ignore_index=True)
  317. # list_sign = list_sign.reset_index()
  318. index_sign = list_sign.index.to_list()
  319. speed_df["flag_press"] = speed_df["simFrame"].apply(lambda x: 1 if x in list_sign["simFrame"] else 0)
  320. speed_df["diff_press"] = speed_df["flag_press"].diff()
  321. # overrate_count = speed_df[speed_df["diff_press"] == -1]["diff_press"].count()
  322. index_list = []
  323. subindex_list = []
  324. for i in range(len(index_sign)):
  325. if not subindex_list or index_sign[i] - index_sign[i - 1] == 1:
  326. subindex_list.append(index_sign[i])
  327. else:
  328. index_list.append(subindex_list)
  329. subindex_list.append(index_sign[i])
  330. index_list.append(subindex_list)
  331. overspeed_count_0_to_10 = 0
  332. overspeed_count_10_to_20 = 0
  333. overspeed_count_20_to_50 = 0
  334. overspeed_count_50_to_ = 0
  335. if index_list[0]:
  336. for i in range(len(index_list)):
  337. left = index_list[i][0]
  338. right = index_list[i][-1]
  339. df_tmp = speed_df.loc[left:right + 1]
  340. max_ratio = ((df_tmp["speed"] - df_tmp["value"]) / df_tmp["value"]).max()
  341. if max_ratio >= 0 and max_ratio < 0.1:
  342. overspeed_count_0_to_10 += 1
  343. elif max_ratio >= 0.1 and max_ratio < 0.2:
  344. overspeed_count_10_to_20 += 1
  345. elif max_ratio >= 0.2 and max_ratio < 0.5:
  346. overspeed_count_20_to_50 += 1
  347. elif max_ratio >= 0.5:
  348. overspeed_count_50_to_ += 1
  349. """
  350. [0, 10) 0,0,1
  351. [10, 20) 0,200,1
  352. 高速、城市快速路:[20, 50) 6,200
  353. 高速、城市快速路:[50,)12,2000
  354. """
  355. overspeed_0_to_10 = {
  356. # 'metric': 'overspeed_0_to_10',
  357. 'metric': 'overspeed10',
  358. 'weight': None,
  359. 'illegal_count': overspeed_count_0_to_10,
  360. 'penalty_points': 0,
  361. 'penalty_money': 0,
  362. 'warning_count': overspeed_count_0_to_10,
  363. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  364. }
  365. overspeed_10_to_20 = {
  366. # 'metric': 'overspeed_10_to_20',
  367. 'metric': 'overspeed10_20',
  368. 'weight': None,
  369. 'illegal_count': overspeed_count_10_to_20,
  370. 'penalty_points': 0,
  371. 'penalty_money': overspeed_count_10_to_20 * 200,
  372. 'warning_count': overspeed_count_10_to_20,
  373. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  374. }
  375. overspeed_20_to_50 = {
  376. # 'metric': 'overspeed_20_to_50',
  377. 'metric': 'overspeed20_50',
  378. 'weight': 6,
  379. 'illegal_count': overspeed_count_20_to_50,
  380. 'penalty_points': overspeed_count_20_to_50 * 6,
  381. 'penalty_money': overspeed_count_20_to_50 * 200,
  382. 'warning_count': 0,
  383. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  384. }
  385. overspeed_50_to_ = {
  386. # 'metric': 'overspeed_50_to_',
  387. 'metric': 'overspeed50',
  388. 'weight': 12,
  389. 'illegal_count': overspeed_count_50_to_,
  390. 'penalty_points': overspeed_count_50_to_ * 12,
  391. 'penalty_money': overspeed_count_50_to_ * 2000,
  392. 'warning_count': 0,
  393. 'penalty_law': '《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。'
  394. }
  395. return overspeed_0_to_10, overspeed_10_to_20, overspeed_20_to_50, overspeed_50_to_
  396. def score_cal_penalty_points(self, penalty_points):
  397. """
  398. # 1_results: 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 100
  399. # 3_results: 0, 15, 30, 45, 100
  400. # 6_results: 0, 30, 100
  401. # 9_results: 0, 15, 100
  402. """
  403. if penalty_points == 0:
  404. score = 100
  405. elif penalty_points >= 12:
  406. score = 0
  407. else:
  408. score = (12 - penalty_points) / 12 * 60
  409. return score
  410. def time_splice(self, start_time, end_time):
  411. str_time = f"[{start_time}s, {end_time}s]"
  412. return str_time
  413. def time_frame_splice(self, start_time, end_time, start_frame, end_frame):
  414. str_time = f"[{start_time}s, {end_time}s], {start_frame}-{end_frame}"
  415. return str_time
  416. def weight_type_cal(self):
  417. # penalty_list = [1, 3, 6, 9, 12]
  418. penalty_list = [1, 3, 6, 12]
  419. sum_penalty = sum(penalty_list)
  420. weight_type_list = [round(x / sum_penalty, 2) for x in penalty_list]
  421. return weight_type_list
  422. def compliance_statistic(self):
  423. # metric analysis
  424. press_line_dict = self.press_solid_line()
  425. run_red_light_dict = self.run_red_light()
  426. overspeed_0_to_10_dict, overspeed_10_to_20_dict, overspeed_20_to_50_dict, overspeed_50_dict = self.overspeed()
  427. df_list = []
  428. if "overspeed10" in self.metric_list:
  429. df_list.append(overspeed_0_to_10_dict)
  430. if "overspeed10_20" in self.metric_list:
  431. df_list.append(overspeed_10_to_20_dict)
  432. if "pressSolidLine" in self.metric_list:
  433. df_list.append(press_line_dict)
  434. if "runRedLight" in self.metric_list:
  435. df_list.append(run_red_light_dict)
  436. if "overspeed20_50" in self.metric_list:
  437. df_list.append(overspeed_20_to_50_dict)
  438. if "overspeed50" in self.metric_list:
  439. df_list.append(overspeed_50_dict)
  440. # generate dataframe and dicts
  441. compliance_df = pd.DataFrame(df_list)
  442. return compliance_df
  443. def compliance_score(self):
  444. """
  445. 待优化
  446. 可以重新构建数据结构,每个判断函数的返回类型为dict
  447. 在多指标统计扣分、罚款时,可以将所有字典合并为一个dataframe,然后求和
  448. """
  449. # initialization
  450. score_type_dict = {}
  451. compliance_df = self.compliance_statistic()
  452. self.illegal_count = int(compliance_df['illegal_count'].sum())
  453. # self.penalty_points = compliance_df['penalty_points'].sum()
  454. # self.penalty_money = compliance_df['penalty_money'].sum()
  455. # self.warning_count = compliance_df['warning_count'].sum()
  456. # self.metric_illegal_list = compliance_df[compliance_df['illegal_count'] > 0]['metric'].tolist()
  457. # self.metric_illegal_count_list = compliance_df['illegal_count'].values.tolist()
  458. #
  459. # self.penalty_points_list = compliance_df['penalty_points'].values.tolist()
  460. # self.penalty_money_list = compliance_df['penalty_money'].values.tolist()
  461. # self.warning_count_list = compliance_df['warning_count'].values.tolist()
  462. self.metric_penalty_points_dict = compliance_df.set_index('metric').to_dict()['penalty_points']
  463. self.metric_illegal_count_dict = compliance_df.set_index('metric').to_dict()['illegal_count']
  464. self.metric_penalty_money_dict = compliance_df.set_index('metric').to_dict()['penalty_money']
  465. self.metric_warning_count_dict = compliance_df.set_index('metric').to_dict()['warning_count']
  466. self.metric_penalty_law_dict = compliance_df.set_index('metric').to_dict()['penalty_law']
  467. # deduct1
  468. if "deduct1" in self.type_list:
  469. deduct1_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 1)]
  470. penalty_points_1 = deduct1_df['penalty_points'].sum()
  471. illegal_count_1 = deduct1_df['illegal_count'].sum()
  472. score_type_dict["deduct1"] = self.score_cal_penalty_points(penalty_points_1)
  473. self.type_illegal_count_dict["deduct1"] = illegal_count_1
  474. # deduct3
  475. if "deduct3" in self.type_list:
  476. deduct3_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 3)]
  477. penalty_points_3 = deduct3_df['penalty_points'].sum()
  478. illegal_count_3 = deduct3_df['illegal_count'].sum()
  479. score_type_dict["deduct3"] = self.score_cal_penalty_points(penalty_points_3)
  480. self.type_illegal_count_dict["deduct3"] = illegal_count_3
  481. # deduct6
  482. if "deduct6" in self.type_list:
  483. deduct6_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 6)]
  484. penalty_points_6 = deduct6_df['penalty_points'].sum()
  485. illegal_count_6 = deduct6_df['illegal_count'].sum()
  486. score_type_dict["deduct6"] = self.score_cal_penalty_points(penalty_points_6)
  487. self.type_illegal_count_dict["deduct6"] = illegal_count_6
  488. # deduct9
  489. if "deduct9" in self.type_list:
  490. deduct9_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 9)]
  491. penalty_points_9 = deduct9_df['penalty_points'].sum()
  492. illegal_count_9 = deduct9_df['illegal_count'].sum()
  493. score_type_dict["deduct9"] = self.score_cal_penalty_points(penalty_points_9)
  494. self.type_illegal_count_dict["deduct9"] = illegal_count_9
  495. # deduct12
  496. if "deduct12" in self.type_list:
  497. deduct12_df = compliance_df[(compliance_df['weight'].isna()) | (compliance_df['weight'] == 12)]
  498. penalty_points_12 = deduct12_df['penalty_points'].sum()
  499. illegal_count_12 = deduct12_df['illegal_count'].sum()
  500. score_type_dict["deduct12"] = self.score_cal_penalty_points(penalty_points_12)
  501. self.type_illegal_count_dict["deduct12"] = illegal_count_12
  502. weight_type_list = self.weight_type_cal()
  503. weight_dict = {
  504. "overspeed10": 0.5,
  505. "overspeed10_20": 0.5,
  506. "pressSolidLine": 1.0,
  507. "runRedLight": 0.5,
  508. "overspeed20_50": 0.5,
  509. "overspeed50": 1.0
  510. }
  511. type_list = ["deduct1", "deduct3", "deduct6", "deduct12"]
  512. if not self.weight_custom: # 客观赋权
  513. self.weight_type_list = weight_type_list
  514. self.weight_type_dict = {key: value for key, value in zip(type_list, weight_type_list)}
  515. self.weight_dict = weight_dict
  516. if self.penalty_points >= 12:
  517. score_compliance = 0
  518. elif sum(score_type_dict.values()) / len(score_type_dict) == 100:
  519. score_compliance = 100
  520. else:
  521. score_type_tmp = [80 if x == 100 else x for key, x in score_type_dict.items()]
  522. score_compliance = np.dot(self.weight_type_list, score_type_tmp)
  523. score_compliance = round(score_compliance, 2)
  524. print("\n[合规性表现及得分情况]")
  525. print(f"合规性得分为:{score_compliance:.2f}分。")
  526. print(f"合规性各分组得分为:{score_type_dict}。")
  527. print(f"合规性各分组权重为:{self.weight_type_list}。")
  528. # print(f"合规性各指标违规次数为:\n{count_metric}。")
  529. # print(f"违法总次数为:{self.illegal_count}。")
  530. # print(f"违法扣分总数为:{self.penalty_points}。")
  531. # print(f"罚款总金额为:{self.penalty_money}。")
  532. # print(f"警告总次数为:{self.warning_count}。")
  533. # print(compliance_df)
  534. return score_compliance, score_type_dict
  535. def _get_weight_distribution(self):
  536. # get weight distribution
  537. weight_distribution = {}
  538. weight_distribution["name"] = self.config.dimension_name["compliance"]
  539. for type in self.type_list:
  540. type_weight_indexes_dict = {key: f"{self.name_dict[key]}({value * 100:.2f}%)" for key, value in
  541. self.weight_dict.items() if
  542. key in self.metric_dict[type]}
  543. weight_distribution_type = {
  544. "weight": f"{self.type_name_dict[type]}({self.weight_type_dict[type] * 100:.2f}%)",
  545. "indexes": type_weight_indexes_dict
  546. }
  547. weight_distribution[type] = weight_distribution_type
  548. return weight_distribution
  549. def compliance_weight_distribution(self):
  550. # get weight distribution
  551. weight_distribution = {}
  552. weight_distribution["name"] = "合规性"
  553. if "deduct1" in self.type_list:
  554. deduct1_weight_indexes_dict = {}
  555. if "overspeed10" in self.metric_list:
  556. deduct1_weight_indexes_dict[
  557. "overspeed10Weight"] = f"超速,但未超过10%({self.weight_dict['overspeed10'] * 100:.2f}%)"
  558. if "overspeed10_20" in self.metric_list:
  559. deduct1_weight_indexes_dict[
  560. "overspeed1020Weight"] = f"超速10%-20%({self.weight_dict['overspeed10_20'] * 100:.2f}%)"
  561. weight_distribution['deduct1'] = {
  562. "deduct1Weight": f"轻微违规(1分)({self.weight_type_dict['deduct1'] * 100:.2f}%)",
  563. "indexes": deduct1_weight_indexes_dict
  564. }
  565. if "deduct3" in self.type_list:
  566. deduct3_weight_indexes_dict = {}
  567. if "pressSolidLine" in self.metric_list:
  568. deduct3_weight_indexes_dict[
  569. "pressSolidLineWeight"] = f"压实线({self.weight_dict['pressSolidLine'] * 100:.2f}%)"
  570. weight_distribution['deduct3'] = {
  571. "deduct3Weight": f"中等违规(3分)({self.weight_type_dict['deduct3'] * 100:.2f}%)",
  572. "indexes": deduct3_weight_indexes_dict
  573. }
  574. if "deduct6" in self.type_list:
  575. deduct6_weight_indexes_dict = {}
  576. if "runRedLight" in self.metric_list:
  577. deduct6_weight_indexes_dict["runRedLightWeight"] = f"闯红灯({self.weight_dict['runRedLight'] * 100:.2f}%)"
  578. if "overspeed20_50" in self.metric_list:
  579. deduct6_weight_indexes_dict[
  580. "overspeed2050Weight"] = f"超速20%-50%({self.weight_dict['overspeed20_50'] * 100:.2f}%)"
  581. weight_distribution['deduct6'] = {
  582. "deduct6Weight": f"危险违规(6分)({self.weight_type_dict['deduct6'] * 100:.2f}%)",
  583. "indexes": deduct6_weight_indexes_dict
  584. }
  585. if "deduct9" in self.type_list:
  586. deduct9_weight_indexes_dict = {}
  587. weight_distribution['deduct9'] = {
  588. "deduct9Weight": f"严重违规(9分)({self.weight_type_dict['deduct6'] * 100:.2f}%)",
  589. "indexes": deduct9_weight_indexes_dict
  590. }
  591. if "deduct12" in self.type_list:
  592. deduct12_weight_indexes_dict = {}
  593. if "overspeed50" in self.metric_list:
  594. deduct12_weight_indexes_dict[
  595. "overspeed50Weight"] = f"超速50%以上({self.weight_dict['overspeed50'] * 100:.2f}%)"
  596. weight_distribution['deduct12'] = {
  597. "deduct12Weight": f"重大违规(12分)({self.weight_type_dict['deduct12'] * 100:.2f}%)",
  598. "indexes": deduct12_weight_indexes_dict
  599. }
  600. return weight_distribution
  601. def report_statistic(self):
  602. score_compliance, score_type_dict = self.compliance_score()
  603. grade_compliance = score_grade(score_compliance)
  604. score_compliance = int(score_compliance) if int(score_compliance) == score_compliance else score_compliance
  605. score_type = [int(n) if int(n) == n else n for key, n in score_type_dict.items()]
  606. # get weight distribution
  607. # weight_distribution = self.compliance_weight_distribution()
  608. weight_distribution = self._get_weight_distribution()
  609. # if self.metric_illegal_list:
  610. # str_illegel_metric = string_concatenate(self.metric_illegal_list)
  611. cnt1 = self.illegal_count
  612. if grade_compliance == '优秀':
  613. comp_description1 = '车辆在本轮测试中无违反交通法规行为;'
  614. elif grade_compliance == '良好':
  615. comp_description1 = f'车辆在本轮测试中共发生{cnt1}次违反交通法规⾏为;'
  616. elif grade_compliance == '一般':
  617. comp_description1 = f'车辆在本轮测试中共有{cnt1}次违反交通法规⾏为,需要提高算法在合规性上的表现;'
  618. elif grade_compliance == '较差':
  619. comp_description1 = f'车辆在本轮测试中共有{cnt1}次违反交通法规⾏为,需要提高算法在合规性上的表现;'
  620. # xx指标得分超过基准线且无违规行为,算法表现良好
  621. # 违规次数 self.illegal_count
  622. # 1分xx次,3分xx次
  623. if cnt1 == 0:
  624. comp_description2 = "车辆在该用例中无违反交通法规行为,算法表现良好。"
  625. else:
  626. str_illegel_type = ""
  627. for type in self.type_list:
  628. if self.type_illegal_count_dict[type] > 0:
  629. str_illegel_type += f'{self.type_name_dict[type]}行为{self.type_illegal_count_dict[type]}次,'
  630. # if "deduct1" in self.type_list:
  631. # if self.type_illegal_count_dict["deduct1"] > 0:
  632. # str_illegel_type += f'轻微违规(1分)行为{self.type_illegal_count_dict["deduct1"]}次,'
  633. #
  634. # if "deduct3" in self.type_list:
  635. # if self.type_illegal_count_dict["deduct3"] > 0:
  636. # str_illegel_type += f'中等违规(3分)行为{self.type_illegal_count_dict["deduct3"]}次,'
  637. #
  638. # if "deduct6" in self.type_list:
  639. # if self.type_illegal_count_dict["deduct6"] > 0:
  640. # str_illegel_type += f'危险违规(6分)行为{self.type_illegal_count_dict["deduct6"]}次,'
  641. #
  642. # if "deduct9" in self.type_list:
  643. # if self.type_illegal_count_dict["deduct9"] > 0:
  644. # str_illegel_type += f'严重违规(9分)行为{self.type_illegal_count_dict["deduct9"]}次,'
  645. #
  646. # if "deduct12" in self.type_list:
  647. # if self.type_illegal_count_dict["deduct12"] > 0:
  648. # str_illegel_type += f'重大违规(12分)行为{self.type_illegal_count_dict["deduct12"]}次,'
  649. str_illegel_type = str_illegel_type[:-1]
  650. comp_description2 = f"车辆在该用例共违反交通法规{cnt1}次。其中{str_illegel_type}。违规行为详情见附录C。"
  651. # data for violations table
  652. if not self.violation_df.empty:
  653. # self.violation_df['time'] = self.violation_df.apply(
  654. # lambda row: self.time_frame_splice(row['start_time'], row['end_time'], row['start_frame'],
  655. # row['end_frame']), axis=1)
  656. self.violation_df['time'] = self.violation_df.apply(
  657. lambda row: self.time_splice(row['start_time'], row['end_time']), axis=1)
  658. df_violations = self.violation_df[['time', 'violation']]
  659. violations_slices = df_violations.to_dict('records')
  660. else:
  661. violations_slices = []
  662. # violations_slices = [{'time': "[1s, 2s]", 'violation': "压实线"},
  663. # {'time': "[10s, 20s]", 'violation': "闯红灯"},
  664. # {'time': "[100s, 200s]", 'violation': "超速"}]
  665. deductPoint_dict = {}
  666. for type in self.type_list:
  667. type_dict = {
  668. "name": self.type_name_dict[type],
  669. "score": score_type_dict[type],
  670. }
  671. type_indexes = {}
  672. for metric in self.metric_list:
  673. type_indexes[metric] = {
  674. # "name": self.name_dict[metric],
  675. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  676. "name": f"{self.name_dict[metric]}",
  677. "times": self.metric_illegal_count_dict[metric],
  678. "deductPoints": self.metric_penalty_points_dict[metric],
  679. "fine": self.metric_penalty_money_dict[metric],
  680. "basis": self.metric_penalty_law_dict[metric]
  681. }
  682. type_dict["indexes"] = type_indexes
  683. deductPoint_dict[type] = type_dict
  684. # deduct1
  685. if "deduct1" in self.type_list:
  686. deduct1_indexes = {}
  687. if "overspeed10" in self.metric_list:
  688. tmp_dict = {
  689. "name": "超速,但未超过10%",
  690. "times": self.metric_illegal_count_dict["overspeed10"],
  691. "deductPoints": self.metric_penalty_points_dict["overspeed10"],
  692. "fine": self.metric_penalty_money_dict["overspeed10"],
  693. "basis": self.metric_penalty_law_dict["overspeed10"]
  694. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  695. }
  696. deduct1_indexes['overspeed10'] = tmp_dict
  697. if "overspeed10_20" in self.metric_list:
  698. tmp_dict = {
  699. "name": "超速10%-20%",
  700. "times": self.metric_illegal_count_dict["overspeed10_20"],
  701. "deductPoints": self.metric_penalty_points_dict["overspeed10_20"],
  702. "fine": self.metric_penalty_money_dict["overspeed10_20"],
  703. "basis": self.metric_penalty_law_dict["overspeed10_20"]
  704. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  705. }
  706. deduct1_indexes['overspeed10_20'] = tmp_dict
  707. deduct1_dict = {
  708. "name": "轻微违规(1分)",
  709. "score": score_type_dict["deduct1"],
  710. "indexes": deduct1_indexes
  711. }
  712. deductPoint_dict["deduct1"] = deduct1_dict
  713. # deduct3
  714. if "deduct3" in self.type_list:
  715. deduct3_indexes = {}
  716. if "pressSolidLine" in self.metric_list:
  717. tmp_dict = {
  718. "name": "压实线",
  719. "times": self.metric_illegal_count_dict["pressSolidLine"],
  720. "deductPoints": self.metric_penalty_points_dict["pressSolidLine"],
  721. "fine": self.metric_penalty_money_dict["pressSolidLine"],
  722. "basis": self.metric_penalty_law_dict["pressSolidLine"]
  723. # "basis": "《中华人民共和国道路交通安全法》第八十二条:机动车在高速公路上行驶,不得有下列行为:(三)骑、轧车行道分界线或者在路肩上行驶。"
  724. }
  725. deduct3_indexes['pressSolidLine'] = tmp_dict
  726. deduct3_dict = {
  727. "name": "中等违规(3分)",
  728. "score": score_type_dict["deduct3"],
  729. "indexes": deduct3_indexes
  730. }
  731. deductPoint_dict["deduct3"] = deduct3_dict
  732. # deduct6
  733. if "deduct6" in self.type_list:
  734. deduct6_indexes = {}
  735. if "runRedLight" in self.metric_list:
  736. tmp_dict = {
  737. "name": "闯红灯",
  738. "times": self.metric_illegal_count_dict["runRedLight"],
  739. "deductPoints": self.metric_penalty_points_dict["runRedLight"],
  740. "fine": self.metric_penalty_money_dict["runRedLight"],
  741. "basis": self.metric_penalty_law_dict["runRedLight"]
  742. # "basis": "《中华人民共和国道路交通安全法实施条例》第四十条:(二)红色叉形灯或者箭头灯亮时,禁止本车道车辆通行。"
  743. }
  744. deduct6_indexes['runRedLight'] = tmp_dict
  745. if "overspeed20_50" in self.metric_list:
  746. tmp_dict = {
  747. "name": "超速20%-50%",
  748. "times": self.metric_illegal_count_dict["overspeed20_50"],
  749. "deductPoints": self.metric_penalty_points_dict["overspeed20_50"],
  750. "fine": self.metric_penalty_money_dict["overspeed20_50"],
  751. "basis": self.metric_penalty_law_dict["overspeed20_50"]
  752. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  753. }
  754. deduct6_indexes['overspeed20_50'] = tmp_dict
  755. deduct6_dict = {
  756. "name": "危险违规(6分)",
  757. "score": score_type_dict["deduct6"],
  758. "indexes": deduct6_indexes
  759. }
  760. deductPoint_dict["deduct6"] = deduct6_dict
  761. # deduct9
  762. if "deduct9" in self.type_list:
  763. deduct9_indexes = {}
  764. if "xx" in self.metric_list:
  765. tmp_dict = {
  766. "name": "-",
  767. "times": "0",
  768. "deductPoints": "0",
  769. "fine": "0",
  770. "basis": "-"
  771. # "basis": "-"
  772. }
  773. deduct9_indexes['xx'] = tmp_dict
  774. deduct9_dict = {
  775. "name": "严重违规(9分)",
  776. "score": 100, # score_type_dict["deduct9"],
  777. "indexes": deduct9_indexes
  778. }
  779. deductPoint_dict["deduct9"] = deduct9_dict
  780. # deduct12
  781. if "deduct12" in self.type_list:
  782. deduct12_indexes = {}
  783. if "overspeed50" in self.metric_list:
  784. tmp_dict = {
  785. "name": "超速50%以上",
  786. "times": self.metric_illegal_count_dict["overspeed50"],
  787. "deductPoints": self.metric_penalty_points_dict["overspeed50"],
  788. "fine": self.metric_penalty_money_dict["overspeed50"],
  789. "basis": self.metric_penalty_law_dict["overspeed50"]
  790. # "basis": "《中华人民共和国道路交通安全法》第四十二条:机动车上道路行驶,不得超过限速标志标明的最高时速。"
  791. }
  792. deduct12_indexes['overspeed50'] = tmp_dict
  793. deduct12_dict = {
  794. "name": "重大违规(12分)",
  795. "score": score_type_dict["deduct12"],
  796. "indexes": deduct12_indexes
  797. }
  798. deductPoint_dict["deduct12"] = deduct12_dict
  799. report_dict = {
  800. "name": "合规性",
  801. "weight": f"{self.weight * 100:.2f}%",
  802. "weightDistribution": weight_distribution,
  803. "score": score_compliance,
  804. "level": grade_compliance,
  805. 'score_type': score_type,
  806. # 'score_metric': score_metric,
  807. 'illegalCount': self.illegal_count,
  808. "description1": comp_description1,
  809. "description2": comp_description2,
  810. "details": deductPoint_dict,
  811. "violations": violations_slices
  812. }
  813. return report_dict
  814. def get_eval_data(self):
  815. df = self.eval_data
  816. return df