可视化步骤
- 一、生成自定义权重对图片的预测类别坐标信息
- 二、创建需要预测的文件夹
- 三、可视化运行
一、生成自定义权重对图片的预测类别坐标信息
新建脚本文件/path/to/your/ultralytics/savetxt.py
放入对应参数运行会得到一个个独立的/path/to/your/runs/detect/output/output1/labels
坐标信息文件夹
请注意这是使用Ultralytics封装的脚本文件
from ultralytics import YOLO
model = YOLO("/path/to/your/weights/best.pt")
model.predict(source="/path/to/your/test/image.jpg",conf=0.45, save=True,save_conf=True,save_txt=True,name='output')
source
后为要预测的图片数据集的的路径save=True
为保存预测结果save_conf=True
为保存坐标信息conf=0.45
为目标置信区间是0.45save_txt=True
为保存txt结果,但是当图片中预测不到任何物体时,不产生txt文件
二、创建需要预测的文件夹
注意一定要是文件夹(directory)
且文件夹内图片数量和名称全部一一对应
- 被预测的图片文件夹:
/path/to/your/directory/images
- 真实类别坐标信息文件夹:
/path/to/your/directory/labels
- 预测类别坐标信息文件夹:
/path/to/your/directory/predict_labels
将挑选的被预测图片放入第一个文件夹
将步骤一生成的类别坐标信息放入第二个文件夹
将被预测图片对应真实的类别坐标信息放入第三个文件
...
├── directory
│ ├── images
│ │ ├── 0000087_01140_d_0000004.jpg
│ │ ├── ...
│ ├── labels
│ │ ├── 0000087_01140_d_0000004.txt
│ │ ├── ...
│ ├── predict_labels
│ │ ├── 0000087_01140_d_0000004.txt
│ │ ├── ...
三、可视化运行
新建/path/to/your/detect.py
填写下述代码
再建立一个可视化结果输出文件夹/path/to/your/vis/
import os
import cv2
import tqdm
import shutil
import numpy as np
def xywh2xyxy(box):
box[:, 0] = box[:, 0] - box[:, 2] / 2
box[:, 1] = box[:, 1] - box[:, 3] / 2
box[:, 2] = box[:, 0] + box[:, 2]
box[:, 3] = box[:, 1] + box[:, 3]
return box
def iou(box1, box2):
x11, y11, x12, y12 = np.split(box1, 4, axis=1)
x21, y21, x22, y22 = np.split(box2, 4, axis=1)
xa = np.maximum(x11, np.transpose(x21))
xb = np.minimum(x12, np.transpose(x22))
ya = np.maximum(y11, np.transpose(y21))
yb = np.minimum(y12, np.transpose(y22))
area_inter = np.maximum(0, (xb - xa + 1)) * np.maximum(0, (yb - ya + 1))
area_1 = (x12 - x11 + 1) * (y12 - y11 + 1)
area_2 = (x22 - x21 + 1) * (y22 - y21 + 1)
area_union = area_1 + np.transpose(area_2) - area_inter
iou = area_inter / area_union
return iou
def draw_box(img, box, color):
cv2.rectangle(img, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), color, thickness=2)
# thickness设置检测框粗细
return img
if __name__ == '__main__':
postfixes = ['jpg', 'JPG'] # 定义要处理的后缀列表
img_path = '/path/to/your/directory/images/0000087_01140_d_0000004.jpg'
label_path = '/path/to/your/directory/labels/0000087_01140_d_0000004.txt'
predict_path = '/path/to/your/directory/predict_labels/0000087_01140_d_0000004.txt'
save_path = '/path/to/your/vis/' # 可视化结果保存的文件夹目录
classes = ['pedestrian', 'people', 'bicycle', 'car'] # 你的自定义数据集类别
detect_color, missing_color, error_color = (0, 255, 0), (0, 0, 255), (255, 0, 0)#(g,b,r)# 不同检测结果下检测框颜色设置
iou_threshold = 0.45 # 与步骤一的conf保持一致
if os.path.exists(save_path):
shutil.rmtree(save_path)
os.makedirs(save_path, exist_ok=True)
all_right_num, all_missing_num, all_error_num = 0, 0, 0
with open('result.txt', 'w') as f_w:
for filename in tqdm.tqdm(os.listdir(img_path)):
postfix = filename.split('.')[-1] # 获取文件名后缀
if postfix.lower() in postfixes: # 判断后缀是否在指定列表中
image = cv2.imread(os.path.join(img_path, filename))
if image is None:
print(f'image:{os.path.join(img_path, filename)} not found.', file=f_w)
continue
h, w = image.shape[:2]
path = filename[:-4] # 去除文件后缀
try:
with open(f'{predict_path}/{path}.txt') as f:
pred = np.array(list(map(lambda x:np.array(x.strip().split(), dtype=np.float32), f.readlines())))
pred[:, 1:5] = xywh2xyxy(pred[:, 1:5])
pred[:, [1, 3]] *= w
pred[:, [2, 4]] *= h
pred = list(pred)
except:
pred = []
try:
with open(f'{label_path}/{path}.txt') as f:
label = np.array(list(map(lambda x:np.array(x.strip().split(), dtype=np.float32), f.readlines())))
label[:, 1:] = xywh2xyxy(label[:, 1:])
label[:, [1, 3]] *= w
label[:, [2, 4]] *= h
except:
print(f'label path:{label_path}/{path}.txt (not found or no target).', file=f_w)
right_num, missing_num, error_num = 0, 0, 0
label_id, pred_id = list(range(label.shape[0])), [] if len(pred) == 0 else list(range(len(pred)))
for i in range(label.shape[0]):
if len(pred) == 0: break
ious = iou(label[i:i+1, 1:], np.array(pred)[:, 1:5])[0]
ious_argsort = ious.argsort()[::-1]
missing = True
for j in ious_argsort:
if ious[j] < iou_threshold: break
if label[i, 0] == pred[j][0]:
image = draw_box(image, pred[j][1:5], detect_color)
pred.pop(j)
missing = False
right_num += 1
break
if missing:
image = draw_box(image, label[i][1:5], missing_color)
missing_num += 1
if len(pred):
for j in range(len(pred)):
image = draw_box(image, pred[j][1:5], error_color)
error_num += 1
all_right_num, all_missing_num, all_error_num = all_right_num + right_num, all_missing_num + missing_num, all_error_num + error_num
cv2.imwrite(f'{save_path}/{path}.{postfix}', image)
print(f'name:{path} right:{right_num} missing:{missing_num} error:{error_num}', file=f_w)
print(f'all_result: right:{all_right_num} missing:{all_missing_num} error:{all_error_num}', file=f_w)
总结起来需要自定义修改的地方如下
def draw_box(img, box, color):
cv2.rectangle(img, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), color, thickness=2)
# thickness设置检测框粗细
return img
postfixes = ['jpg', 'JPG'] # 定义要处理的后缀列表
img_path = '/path/to/your/directory/images/0000087_01140_d_0000004.jpg'
label_path = '/path/to/your/directory/labels/0000087_01140_d_0000004.txt'
predict_path = '/path/to/your/directory/predict_labels/0000087_01140_d_0000004.txt'
save_path = '/path/to/your/vis/' # 可视化结果保存的文件夹目录
classes = ['pedestrian', 'people', 'bicycle', 'car'] # 你的自定义数据集类别
detect_color, missing_color, error_color = (0, 255, 0), (0, 0, 255), (255, 0, 0)#(g,b,r)# 不同检测结果下检测框颜色设置
iou_threshold = 0.45 # 与步骤一的conf保持一致
不同颜色检测框代表的模型权重对于预测图片的检测情况
- 绿色:真正例(TP),指检测到的目标与实际目标之间的匹配,这意味着检测到的目标在位置和类别上都与实际目标匹配,即正确检出;
- 蓝色:假正例(FP),指模型错误地将负例(非目标)样本预测为正例(目标),即误检;
- 红色:假负例(FN),指模型未能检测到实际存在的目标,即漏检。
最终生成的图片位于:/path/to/your/vis/0000087_01140_d_0000004.jpg