(recall)
1、预测数据
使⽤ yolov5 预测输出的是带标记框的图⽚,所以需要先将预测的数据输出为⽂本格式,如json。 可以参考我之前的博客 json⽂件格式如下图
[ {
\"name\":\"01_05_0002.jpg\ \"category\":\"1\ \"bbox\":[ 3550, 1813, 4106, 2468 ],
\"score\":0.9482421875 }, {
\"name\":\"01_05_0002.jpg\ \"category\":\"1\ \"bbox\":[ 4041, 1655, 4570, 2291 ],
\"score\":0.9521484375 }]
2、测试图的标记数据
因为使⽤的是 yolov5 ,所以测试集的标记数据和训练集⼀样都是 txt 格式的标注数据
3、将预测数据和标注数据匹配 ⼀个测试图中可能存在好⼏个⽬标物,那预测数据和标注数据中就会存在好⼏个标注框,计算两个框的交集⾯积,交集⾯积最⼤的两个框才是互相匹配 的。 计算两个矩形框的交集⾯积 def label_area_detect(label_bbox_list, detect_bbox_list): x_label_min, y_label_min, x_label_max, y_label_max = label_bbox_list x_detect_min, y_detect_min, x_detect_max, y_detect_max = detect_bbox_list if (x_label_max <= x_detect_min or x_detect_max < x_label_min) or ( y_label_max <= y_detect_min or y_detect_max <= y_label_min): return 0 else: lens = min(x_label_max, x_detect_max) - max(x_label_min, x_detect_min) wide = min(y_label_max, y_detect_max) - max(y_label_min, y_detect_min) return lens * wide 4、多分类 precision 和 recall 的计算 将预测数据和标注数据匹配算出⼀个 N*N 的矩阵 4、代码 import osimport json import numpy as npfrom PIL import Image # class name classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']# 初始化⼆维0数组 result_list = np.array(np.zeros([len(classes), len(classes)]))# 获取图⽚宽⾼ def get_image_width_high(full_image_name): image = Image.open(full_image_name) image_width, image_high = image.size[0], image.size[1] return image_width, image_high # 读取原始标注数据 def read_label_txt(full_label_name, full_image_name): fp = open(full_label_name, mode=\"r\") lines = fp.readlines() image_width, image_high = get_image_width_high(full_image_name) object_list = [] for line in lines: array = line.split() x_label_min = (float(array[1]) - float(array[3]) / 2) * image_width x_label_max = (float(array[1]) + float(array[3]) / 2) * image_width y_label_min = (float(array[2]) - float(array[4]) / 2) * image_high y_label_max = (float(array[2]) + float(array[4]) / 2) * image_high bbox = [round(x_label_min, 2), round(y_label_min, 2), round(x_label_max, 2), round(y_label_max, 2)] category = int(array[0]) obj_info = { 'category' : category, 'bbox' : bbox } object_list.append(obj_info) return object_list # 计算交集⾯积 def label_area_detect(label_bbox_list, detect_bbox_list): x_label_min, y_label_min, x_label_max, y_label_max = label_bbox_list x_detect_min, y_detect_min, x_detect_max, y_detect_max = detect_bbox_list if (x_label_max <= x_detect_min or x_detect_max < x_label_min) or ( y_label_max <= y_detect_min or y_detect_max <= y_label_min): return 0 else: lens = min(x_label_max, x_detect_max) - max(x_label_min, x_detect_min) wide = min(y_label_max, y_detect_max) - max(y_label_min, y_detect_min) return lens * wide # label 匹配 detect def label_match_detect(image_name, label_list, detect_list): for label in label_list: area_max = 0 area_category = 0 label_category = label['category'] label_bbox = label['bbox'] for detect in detect_list: if detect['name'] == image_name: detect_bbox = detect['bbox'] area = label_area_detect(label_bbox, detect_bbox) if area > area_max: area_max = area area_category = detect['category'] result_list[int(label_category)][classes.index(str(area_category))] += 1 def main(): image_path = '../image_data/seed/test/images/' # 图⽚⽂件路径 label_path = '../image_data/seed/test/labels/' # 标注⽂件路径 detect_path = 'result.json' # 预测的数据 precision = 0 # 精确率 recall = 0 # 召回率 # 读取 预测 ⽂件数据 with open(detect_path, 'r') as load_f: detect_list = json.load(load_f) # 读取图⽚⽂件数据 all_image = os.listdir(image_path) for i in range(len(all_image)): full_image_path = os.path.join(image_path, all_image[i]) # 分离⽂件名和⽂件后缀 image_name, image_extension = os.path.splitext(all_image[i]) # 拼接标注路径 full_label_path = os.path.join(label_path, image_name + '.txt') # 读取标注数据 label_list = read_label_txt(full_label_path, full_image_path) # 标注数据匹配detect label_match_detect(all_image[i], label_list, detect_list) # print(result_list) for i in range(len(classes)): row_sum, col_sum = sum(result_list[i]), sum(result_list[r][i] for r in range(len(classes))) precision += result_list[i][i] / float(col_sum) recall += result_list[i][i] / float(row_sum) print(f'precision: {precision / len(classes) * 100}% recall: {recall / len(classes) * 100}%') if __name__ == '__main__': main() 输出: 因篇幅问题不能全部显示,请点此查看更多更全内容