感知模型召回率、精确率计算(终)
发布时间
阅读量:
阅读量
Python计算3D感知模型召回率、精确率
- 步骤1:格式化数据
- 步骤2:统计感知结果、标注数据中各类目标总数
- 步驟3:统计各分类召回样本为正的个数
- 步骤4:计算各分类召回率、精确率
上篇文章讲述目标框与感知框交并比计算方法,本文将详细说明召回率与精确率的计算方式。
步骤1:格式化数据
格式化数据分为两步,第一步:格式化标注数据,第二步:格式化感知结果,具体格式如下:
# 标注数据的格式为:
# {
# '文件名': [{'class': value, 'center': [x, y, z], 'size': [l, w, h], 'rotation': value, 'used': False}, ...],
# '文件名': [{'class': value, 'center': [x, y, z], 'size': [l, w, h], 'rotation': value, 'used': False}, ...],
# }
def _format_mark_data(self):
_format_mark_data = {}
# mark_data 格式为 {"file_name": [["class", [x, y, z], [l, w , h], rotation], ...]}
for file_name, targets in self.mark_data.items():
bounding_boxes = []
for data in targets:
bounding_boxes.append({"class_name": data[0], "center": data[1], "size": data[2],
"rotation": data[3], "used": False})
_format_mark_data[file_name] = bounding_boxes
return _format_mark_data
# 感知结果格式为:
# {
# "class": [
# {
# 'file_name': 'file_name'
# 'confidence': value,
# 'center': [x, y, z],
# 'size': [l, w, h],
# 'rotation': value,
# },
# ...
# ]
# ...
# }
def _format_res_data(self):
# res_data 格式为 {"file_name": [["class", [x, y, z], [l, w , h], rotation], ...]}
_format_res_data = {}
for file_name, targets in self.res_data.items():
for target in targets:
if target[0] not in _format_res_data.keys():
_format_res_data[target[0]] = list()
_format_res_data[target[0]].append(
{
'file_name': file_name,
'confidence': target[4],
'center': target[1],
'size': target[2],
'rotation': target[3],
'used': False
}
)
# 策略: 将置信度降序排列,确保置信度高的数据优先计算以降低错误率
for class_name, boxes in _format_res_data.items():
boxes.sort(key=lambda box: float(box['confidence']), reverse=True)
_format_res_data[class_name] = boxes
return _format_res_data
步骤2:统计感知结果、标注数据中各类目标总数
标注数据中分类目标的数量可以理解成:TP + FN
感知数据中分类目标的数量可以理解成:TP + FP
def _compute_target_counts(self):
"""
统计标注数据、感知数据中各分类的数量
:return: 返回格式为{“class”: count}
"""
def _compute(target_data):
_res = dict()
for _value in target_data.values():
for _target in _value:
_class_name = _target[0]
if _class_name in _res.keys():
_res[_class_name] += 1
else:
_res[_class_name] = 1
return _res
return _compute(self.mark_data), _compute(self.res_data)
步驟3:统计各分类召回样本为正的个数
遍历步骤1中的结果,统计分类TP数量
def _compute_true_positive_counts(self, compute_format_mark_data, compute_format_res_data):
"""
计算召回样本中为TP的个数
:param compute_format_mark_data: 标注格式化数据
:param compute_format_res_data: 感知格式化数据
:return: 分类匹配为正样本的个数
"""
_true_positive = {}
# 步骤一: 遍历标注数据中所有出现过的分类, 若感知数据中未出现此分类,则分类tp个数为0
# cate_map为标注类别与感知类别的映射关系
_loop_values = set(self.cate_map.values()) if self.is_vision else self.cate_map.keys()
for class_name in _loop_values:
_true_positive[class_name] = 0
# if class_name not in compute_format_res_data.keys():
# continue
# 根据标注的key获取结果中可能存在的key列表,将所有感知结果取出
_detections = list()
if self.is_vision:
_detections = compute_format_res_data.get(class_name, list())
else:
_res_keys_list = get_res_type_list_with_mark_type(class_name)
for _key in _res_keys_list:
_detections = _detections + compute_format_res_data.get(_key, list())
# 步骤二: 取感知格式化结果中类别为class_name的数据,遍历数据与标注数据对比,统计tp个数
for detection in _detections:
# 取当前数据所在的文件名,通过文件名取出文件中所有标注数据
_file_name = detection["file_name"]
# 记录当前感知框与标注框匹配IOU最大值,分类相同IOU值最大则认为匹配成功
_iou_max = -1 # 记录最佳匹配IOU值
# 记录匹配成功的标注对象,需要通过此变量将used值设置为True
_gt_match = -1 # 记录最佳匹配对象值
# 遍历标注格式化结果,与当前感知框进行匹配
for label in compute_format_mark_data[_file_name]:
# 只有分类映射正确 且 used值为False时才进行匹配
if label["class_name"] == class_name and not label['used']:
# 计算IOU, 传参格式 (center(x, y, z), box_size(l, w, h), heading_angle)
_, _iou_3d = box3d_iou(
(tuple(label["center"]), tuple(label["size"]), label["rotation"] / 180),
(tuple(detection["center"]), tuple(detection["size"]), detection["rotation"] / 180),
self.coordinate_axis
)
# 记录的最大IOU与当前IOU比较
if _iou_3d > _iou_max:
_iou_max = _iou_3d
_gt_match = label
# 获取当前分类IOU阈值
min_overlap = float(self.classes_iou.get(class_name, iou_default_value)) # 默认IOU值
# 若IOU大于阈值且当前数据未被使用,则tp加1,used值设置为True
if _iou_max >= min_overlap and not _gt_match['used']:
_gt_match['used'] = True
detection['used'] = True
_true_positive[class_name] += 1
return _true_positive
步骤4:计算各分类召回率、精确率
结合步骤2、步骤3的结果,计算分类召回率、精确率数值
_compute_res = dict()
for key in set(self.cate_map.values()):
_compute_res[key] = {
"tp_count": _tp.get(key, 0),
"recall_count": _res_data_count.get(key, 0),
"mark_count": _mark_data_count.get(key, 0),
"recall": "%.4f" % (_tp.get(key, 0) / _mark_data_count.get(key, 1)), # 召回率 识别为正样本数量/正样本总数
"precision": 0 if _res_data_count.get(key, 0) == 0 else "%.4f" % (_tp.get(key, 0) / _res_data_count.get(key, 0))
}
# _compute_res 为所有结果
全部评论 (0)
还没有任何评论哟~
