物体分类和目标检测性能评价指标
参考链接:
- https://blog.csdn.net/katherine_hsr/article/details/79266880
- https://github.com/AlexeyAB/darknet#how-to-compile-on-windows
- https://www.jianshu.com/p/665f9f168eff
不要走开.....看下面
python代码:
##-*- coding:utf-8-*-
#通用目标检测模型评价脚本 For unique class
#评价指标:1) AP for the unigue class
# 2) AVE_IOU
# 3) F1-Score
# 4) TP FP FN
# 5) Precision
# 6) Recall
#Author: SyGoing
#Date: 2018.08.16-2018.08.17(Have finished,Just wait for TEST)
#Refer: The Method of VOC DataSet
#input:
# 1 Test images
# 2 Gound Truth labels
# 3 detection result
#output: AP Recall Precision TP(正确) FP(误检) FN(漏检) AVE_IOU F1-score
import numpy as np
import xml.etree.ElementTree as ET
import cv2
import os
#类型ID
classes = ["person", "car"]
def searchFile(filename,fieltype,filelist):
search_id=-1
for file in filelist:
name= os.path.splitext(file)[0] # 文件名
type= os.path.splitext(file)[1] # 文件扩展名
search_id+=1
if filename==name and fieltype==type:
break
return filelist[search_id]
def getLabelNum(objs_t,classname):
count=0
for obj in objs_t:
if obj['name']==classname:
count+=1
return count
def voc_ap(rec, prec, use_07_metric=False):
""" ap = voc_ap(rec, prec, [use_07_metric])
Compute VOC AP given precision and recall.
If use_07_metric is true, uses the
VOC 07 11 point method (default:False).
"""
if use_07_metric:
# 11 point metric
ap = 0.
for t in np.arange(0., 1.1, 0.1):
if np.sum(rec >= t) == 0:
p = 0
else:
p = np.max(prec[rec >= t])
ap = ap + p / 11.
else:
# correct AP calculation
# first append sentinel values at the end
mrec = np.concatenate(([0.], rec, [1.]))
mpre = np.concatenate(([0.], prec, [0.]))
# compute the precision envelope
for i in range(mpre.size - 1, 0, -1):
mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
# to calculate area under PR curve, look for points
# where X axis (recall) changes value
i = np.where(mrec[1:] != mrec[:-1])[0]
# and sum (\Delta recall) * prec
ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
return ap
#ground truth in VOC xml for per image
def loadGroundTruth_XML(xmlfile):
objects = []
""" groundType=0:Parse a PASCAL VOC xml file """
tree = ET.parse(xmlfile)
for obj in tree.findall('object'):
obj_struct = {}
obj_struct['name'] = obj.find('name').text
bbox = obj.find('bndbox')
obj_struct['bbox'] = [int(bbox.find('xmin').text),
int(bbox.find('ymin').text),
int(bbox.find('xmax').text),
int(bbox.find('ymax').text)]
objects.append(obj_struct)
return objects
#marked by yolo_mark for per image
def loadGroundTruth_TXT(txtfile,width,height):
objects = []
""" groundType=1:Parse a normal txt file :the file is yolo """
with open(txtfile, 'r') as f:
lines = f.readlines()
splitlines = [x.strip().split(' ') for x in lines]
for obj in splitlines:
obj_struct = {}
obj_struct['name']=classes[obj[0]]
w = float(obj[3]) * float(width)
h = float(obj[4])* float(height)
xmin = float(obj[1]) * float(width) - w / 2
ymin = float(obj[2]) * float(height) - h / 2
xmax = w + xmin
ymax = h + ymin
obj_struct['bbox'] = [int(xmin), int(ymin), int(xmax), int(ymax)]
objects.append(obj_struct)
return objects
#per image detfile by txt
def loadDets(detfile):
objects = []
with open(detfile, 'r') as f:
lines = f.readlines()
splitlines = [x.strip().split(' ') for x in lines]
for obj in splitlines:
obj_struct = {}
obj_struct['name'] = classes[obj[0]]
obj_struct['conf']=obj[1]
xmin=obj[2]
ymin=obj[3]
xmax=obj[4]+xmin
ymax=obj[5]+ymin
obj_struct['bbox'] = [int(xmin), int(ymin), int(xmax), int(ymax)]
objects.append(obj_struct)
return objects
def iou(box_t,box_d):
inter_xmin = np.maximum(box_d[0], box_t[0])
inter_ymin = np.maximum(box_d[1], box_t[1])
inter_xmax = np.minimum(box_d[2], box_t[2])
inter_ymax = np.minimum(box_d[3], box_t[3])
inter_h = inter_ymax - inter_ymin
inter_w = inter_xmax - inter_xmin
uni = ((box_t[2] - box_t[0] + 1.) * (box_t[3] - box_t[1] + 1.) +
(box_d[2] - box_d[0] + 1.) * (box_d[3] - box_d[1] + 1.) - inter_h * inter_w)
return inter_h * inter_w / uni
def ObjectEval(detpath,truthpath,imagePath,className,truthtype,ovthresh=0.5,use_07_metric=True):
npos=0
fp=0
tp=0
det_num=0
ave_iou=0
#1 Truth Dets Images
truth_annos=os.listdir(truthpath)
detsfiles=os.listdir(detpath)
imagefiles=os.listdir(imagePath)
for truth in truth_annos:
filenamet = os.path.splitext( truth)[0] # 文件名
filetypet = os.path.splitext( truth)[1] # 文件扩展名
if filetypet=='.xml':
objects_t=loadGroundTruth_XML(os.path.join(truthpath,truth))
detfile = searchFile(filenamet, '.txt', detsfiles)
objects_d=loadDets(os.path.join(detpath,detfile))
num = getLabelNum(objects_t, className)
npos+=num
for objd in objects_d:
if objd['name']==className:
det_num+=1
if num==0:
fp+=1
else:
max_iou=-1
for objt in objects_t:
if objt['name']==className:
box_t=np.array(objt['bbox'].astype(float))
box_d=np.array(objd['bbox'].astype(float))
IOU= iou(box_d,box_t)
if IOU>max_iou:
max_iou=IOU
if max_iou>ovthresh:
ave_iou+=max_iou
tp+=1
else:
fp+=1
ave_iou=ave_iou/(tp+fp)
prec=tp/(tp+fp)
rec=tp/npos
F1_score=2*prec*rec/(prec+rec)
ap=voc_ap(rec, prec, use_07_metric)
return rec, prec,F1_score, ap,ave_iou
def ObjectEvalTEST1(detpath,truthpath,imagePath,className,truthtype,ovthresh=0.5,use_07_metric=True):
npos = 0
fp = 0
tp = 0
det_num = 0
ave_iou = 0
# 1 Truth Dets Images
truth_annos = os.listdir(truthpath)
detsfiles = os.listdir(detpath)
imagefiles = os.listdir(imagePath)
for truth in truth_annos:
filenamet = os.path.splitext(truth)[0] # 文件名
filetypet = os.path.splitext(truth)[1] # 文件扩展名
# R = [obj for obj in recs[imagename] if obj['name'] == classname]
objects_t = []
objects_d = []
if truthtype == 0 and filetypet == '.xml':
objects_t = loadGroundTruth_XML(os.path.join(truthpath, truth))
elif truthtype == 1 and filetypet == '.txt':
imgFile = searchFile(filenamet, '.jpg', imagefiles)
img = cv2.imread(os.path.join(imagePath, imgFile))
objects_t = loadGroundTruth_TXT(os.path.join(truthpath, truth), img.shape[1], img.shape[0])
num = getLabelNum(objects_t, className)
npos += num
detfile = searchFile(filenamet, '.txt', detsfiles)
objects_d = loadDets(os.path.join(detpath, detfile))
for objd in objects_d:
if objd['name'] == className:
det_num += 1
if num == 0:
fp += 1
else:
max_iou = -1
for objt in objects_t:
if objt['name'] == className:
box_t = np.array(objt['bbox'].astype(float))
box_d = np.array(objd['bbox'].astype(float))
IOU = iou(box_d, box_t)
if IOU > max_iou:
max_iou = IOU
if max_iou > ovthresh:
ave_iou += max_iou
tp += 1
else:
fp += 1
ave_iou = ave_iou / (tp + fp)
prec = tp / (tp + fp)
rec = tp / npos
F1_score = 2 * prec * rec / (prec + rec)
ap = voc_ap(rec, prec, use_07_metric)
return rec, prec, F1_score, ap, ave_iou
def ObjectEvalTEST2(detpath, truthpath, imagePath, className, truthtype, ovthresh=0.5, use_07_metric=True):
npos = 0
fp = 0
tp = 0
fn=0
det_num = 0
ave_iou = 0
# 1 Truth and Dets and Images
truth_annos = os.listdir(truthpath)
detsfiles = os.listdir(detpath)
imagefiles = os.listdir(imagePath)
for truth in truth_annos:
filenamet = os.path.splitext(truth)[0] # 文件名
filetypet = os.path.splitext(truth)[1] # 文件扩展名
objects_t = []
if truthtype == 0 and filetypet == '.xml':
objects_t = loadGroundTruth_XML(os.path.join(truthpath, truth))
elif truthtype == 1 and filetypet == '.txt':
imgFile = searchFile(filenamet, '.jpg', imagefiles)
img = cv2.imread(os.path.join(imagePath, imgFile))
objects_t = loadGroundTruth_TXT(os.path.join(truthpath, truth), img.shape[1], img.shape[0])
detfile = searchFile(filenamet, '.txt', detsfiles)
objects_d = loadDets(os.path.join(detpath, detfile))
ValidTruth = [X for X in objects_t if X['name'] == className]
ValidDets = [X for X in objects_d if X['name'] == className]
numt=len(ValidTruth)
numd=len(ValidDets)
npos+=numt
if numd==0 and numt!=0:
fn+=numt
continue
elif numd!=0 and numt==0:
fp+=numd
continue
elif numd==0 and numt==0:
continue
else:
for objd in objects_d:
if objd['name'] == className:
det_num += 1
max_iou = -1
for objt in objects_t:
if objt['name'] == className:
box_t = np.array(objt['bbox'].astype(float))
box_d = np.array(objd['bbox'].astype(float))
IOU = iou(box_d, box_t)
if IOU > max_iou:
max_iou = IOU
if max_iou > ovthresh:
ave_iou += max_iou
tp += 1
else:
fp += 1
ave_iou = ave_iou / float(tp + fp)
prec = float(tp) / float(tp + fp)
rec = float(tp) / float(npos)
F1_score = 2 * prec * rec / (prec + rec)
ap = voc_ap(rec, prec, use_07_metric)
return rec, prec, ap, ave_iou,F1_score,tp,fp,fn