欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【工具代码】目标检测绘制评估曲线

程序员文章站 2022-06-21 14:49:29
...

draw.py

# -*- coding: UTF-8 -*-
from pr import *
clas= ['ignore', 'pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning_tricycle', 'bus', 'motor'] # 类别
prediction_file=["FRCNN.txt", 'RetinaNet.txt', 'ourResult.txt', 'SSD.txt', "CenterNet.txt"] # 放在Prediction里面"Faster_RCNN.txt"
prediction_algorithm=["FRCNN", 'RetinaNet', 'ourResult', 'SSD', "CenterNet"] # 对应上面的文件的算法名称
use_07_metric=[False, False, False, False, False]
ground_truth_file=["gt.txt", 'gt.txt', 'gt.txt', 'gt.txt', "gt.txt"] # 放在Ground Truth里面

# 绘制出了各个类别的Precision-Recall曲线
draw_pr(prediction_file,prediction_algorithm,ground_truth_file,clas,use_07_metric)

pr.py

# -*- coding: UTF-8 -*-
import numpy as np
import math
import matplotlib.pyplot as plt

def get_pr_data_map(prediction_file,ground_truth_file,cls_name,use_07_metric,ovthresh=0.5):
    with open(ground_truth_file, 'r') as f:####读取各个算法的gt.txt文件
        lines_gt = f.readlines()          #gt.txt的每一行,line_gt为一维数组
    with open(prediction_file, 'r') as f:####读取各个算法的pre.txt文件
        lines_pre = f.readlines()         #读取pre.txt的每一行,lines_gt为一维数组
            #根据txt文件中每一行的空格进行划分,splitlines_gt为二维数组,行为每一行的数据,列为每一行的数据划分
    splitlines_gt = [x.strip().split(' ') for x in lines_gt]
    #imagenames_gt为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到imagenames_gt中
    imagenames_gt = [ x[0] for x in splitlines_gt ] 
    class_recs = {}       
#     #BB_gt为二维数组,当第二列的类别与遍历的类别数相同时,将第二列之后的加入到BB_gt中
    BB_gt=np.array([[math.ceil(float(z)) for z in x[2:]] for x in splitlines_gt])
    for i in range(len(imagenames_gt)):
        #如果类别中没有该遍历的类别,则更新
        if imagenames_gt[i] not in class_recs:
            class_recs.update({imagenames_gt[i]:{"bbox":[],"det":[],"difficult":[]}})
        #否则将BB_gt[i]插入到类别框信息中
        class_recs[imagenames_gt[i]]["bbox"].append(BB_gt[i])
        class_recs[imagenames_gt[i]]["det"].append(False)
        class_recs[imagenames_gt[i]]["difficult"].append(False)
            #npos为imagenames_gt的长度
    npos=len(imagenames_gt)
    splitlines_pre = [x.strip().split(' ') for x in lines_pre] 
    #image_ids为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到image_ids中     
    image_ids = [x[0] for x in splitlines_pre] 
    #提取该类别预测框的置信度,当第二列的类别与遍历的类别数相同时,将第三列加入到confidence中
    confidence = np.array([float(x[2]) for x in splitlines_pre]) 
    #提取该类别预测框的bounging-boxes(二维数组),当第二列的类别与遍历的类别数相同时,将第三列之后的BBOX坐标插入
    BB_pre = np.array([[float(z) for z in x[3:]] for x in splitlines_pre]) 
    #按置信度大小将其索引从小到大排序(生成有顺序的一维数组)
    sorted_ind = np.argsort(-confidence)
    #按置信度大小将置信度从小到大排序(生成有顺序的一维数组)
    sorted_scores = np.sort(-confidence)
    #根据索引排序相应的bbox的坐标值(生成按置信度大小排列的二维数组)
    BB_pre = BB_pre[sorted_ind, :]
    #按置信度大小重新排列image_ids
    image_ids = [image_ids[x] for x in sorted_ind]
    nd = len(image_ids)
    tp = np.zeros(nd)
    fp = np.zeros(nd)
    pr_data_map=[]
    for d in range(nd):
        if class_recs.get(image_ids[d]):
            #print(image_ids[d])
            R = class_recs[image_ids[d]]
            #print(R)
            bb = np.array(BB_pre[d, :]).astype(float)#按置信度顺序提取bounding box
            ovmax = -np.inf#ovmax为负无穷大的数
            BBGT = np.array(R['bbox']).astype(float)#按置信度顺序提取groudtruth bbox

            #计算iou
            if BBGT.size > 0:
                ixmin = np.maximum(BBGT[:, 0], bb[0])
                iymin = np.maximum(BBGT[:, 1], bb[1])
                ixmax = np.minimum(BBGT[:, 2], bb[2])
                iymax = np.minimum(BBGT[:, 3], bb[3])
                iw = np.maximum(ixmax - ixmin + 1., 0.)
                ih = np.maximum(iymax - iymin + 1., 0.)
                inters = iw * ih

                uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                       (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                       (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

                overlaps = inters / uni#重叠率
                ovmax = np.max(overlaps)#按重叠率的大小从大到小排序重叠率
                jmax = np.argmax(overlaps)#根据重叠率大小重新排序的索引

            if ovmax > ovthresh:#ovthresh=0.5阈值为0.5,判断tp和fp
                if not R['difficult'][jmax]:
                    if not R['det'][jmax]:
                        tp[d] = 1.
                        R['det'][jmax] = 1
                    else:
                        fp[d] = 1.
            else:
                fp[d] = 1.
        else:
            fp[d]=1.


        
    fp = np.cumsum(fp)
    tp = np.cumsum(tp)
    #rec=tp/正样本数
    rec = tp / float(npos)
    print(len(rec))
    # print(type(rec))
    #perc=tp/(tp+fp)
    prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
    print(len(prec))
    # print(type(prec))
    ap = voc_ap(rec, prec, use_07_metric)
    print(ap)
    pr_data_map=np.array([rec.tolist(),prec.tolist()])#,ap.tolist()]
    pr_data_map=pr_data_map.tolist()

    #print(pr_data_map)
    return pr_data_map 


def get_pr_data(prediction_file,ground_truth_file,cls_name,use_07_metric,ovthresh=0.5):
    with open(ground_truth_file, 'r') as f:####读取各个算法的gt.txt文件
        lines_gt = f.readlines()          #gt.txt的每一行,line_gt为一维数组
    with open(prediction_file, 'r') as f:####读取各个算法的pre.txt文件
        lines_pre = f.readlines()         #读取pre.txt的每一行,lines_gt为一维数组

    pr_data={}
    for cls_num in range(len(cls_name)): #遍历每个类别数
        # print(cls_num)
    #ground_truth  
        #根据txt文件中每一行的空格进行划分,splitlines_gt为二维数组,行为每一行的数据,列为每一行的数据划分
        splitlines_gt = [x.strip().split(' ') for x in lines_gt]
        #imagenames_gt为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到imagenames_gt中
        imagenames_gt = [ x[0] for x in splitlines_gt if int(x[1])==cls_num] 
        #print(imagenames_gt)           
        #BB_gt为二维数组,当第二列的类别与遍历的类别数相同时,将第二列之后的加入到BB_gt中
        BB_gt=np.array([[math.ceil(float(z)) for z in x[2:]] for x in splitlines_gt if int(x[1])==cls_num])
        #创建class_recs数组
        class_recs = {}
        for i in range(len(imagenames_gt)):
            #如果类别中没有该遍历的类别,则更新
            if imagenames_gt[i] not in class_recs:
                class_recs.update({imagenames_gt[i]:{"bbox":[],"det":[],"difficult":[]}})
            #否则将BB_gt[i]插入到类别框信息中
            class_recs[imagenames_gt[i]]["bbox"].append(BB_gt[i])
            class_recs[imagenames_gt[i]]["det"].append(False)
            class_recs[imagenames_gt[i]]["difficult"].append(False)
            #print(class_recs[imagenames_gt[i]])
        #npos为imagenames_gt的长度
        npos=len(imagenames_gt)
    
    #prediction 
        #对预测框的每一行根据空格划分,splitlines_pre为二维数组   
        splitlines_pre = [x.strip().split(' ') for x in lines_pre] 
        #image_ids为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到image_ids中     
        image_ids = [x[0] for x in splitlines_pre if int(x[1])==cls_num] 
        #提取该类别预测框的置信度,当第二列的类别与遍历的类别数相同时,将第三列加入到confidence中
        confidence = np.array([float(x[2]) for x in splitlines_pre if int(x[1])==cls_num]) 
        #提取该类别预测框的bounging-boxes(二维数组),当第二列的类别与遍历的类别数相同时,将第三列之后的BBOX坐标插入
        BB_pre = np.array([[float(z) for z in x[3:]] for x in splitlines_pre if int(x[1])==cls_num]) 
        #按置信度大小将其索引从小到大排序(生成有顺序的一维数组)
        sorted_ind = np.argsort(-confidence)
        #按置信度大小将置信度从小到大排序(生成有顺序的一维数组)
        sorted_scores = np.sort(-confidence)
        #根据索引排序相应的bbox的坐标值(生成按置信度大小排列的二维数组)
        BB_pre = BB_pre[sorted_ind, :]
        #按置信度大小重新排列image_ids
        image_ids = [image_ids[x] for x in sorted_ind]
        #该类别的预测框的数量
        nd = len(image_ids)
        tp = np.zeros(nd)#将长度为nd数组置0
        fp = np.zeros(nd)

        # print(nd)###############################################################################################################
        for d in range(nd):
            #按置信度顺序提取类别框
            #print(image_ids[d].get(image_ids[d]))
            # if class_recs[image_ids[d]] not in class_recs:
            if class_recs.get(image_ids[d]):
                #print(image_ids[d])
                R = class_recs[image_ids[d]]
                #print(R)
                bb = np.array(BB_pre[d, :]).astype(float)#按置信度顺序提取bounding box
                ovmax = -np.inf#ovmax为负无穷大的数
                BBGT = np.array(R['bbox']).astype(float)#按置信度顺序提取groudtruth bbox

                #计算iou
                if BBGT.size > 0:
                    ixmin = np.maximum(BBGT[:, 0], bb[0])
                    iymin = np.maximum(BBGT[:, 1], bb[1])
                    ixmax = np.minimum(BBGT[:, 2], bb[2])
                    iymax = np.minimum(BBGT[:, 3], bb[3])
                    iw = np.maximum(ixmax - ixmin + 1., 0.)
                    ih = np.maximum(iymax - iymin + 1., 0.)
                    inters = iw * ih

                    uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                           (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                           (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

                    overlaps = inters / uni#重叠率
                    ovmax = np.max(overlaps)#按重叠率的大小从大到小排序重叠率
                    jmax = np.argmax(overlaps)#根据重叠率大小重新排序的索引

                if ovmax > ovthresh:#ovthresh=0.5阈值为0.5,判断tp和fp
                    if not R['difficult'][jmax]:
                        if not R['det'][jmax]:
                            tp[d] = 1.
                            R['det'][jmax] = 1
                        else:
                            fp[d] = 1.
                else:
                    fp[d] = 1.
            else:
                #print("*************************************************************"+str(d))
                fp[d]=1.


            
        fp = np.cumsum(fp)
        tp = np.cumsum(tp)
        #rec=tp/正样本数
        rec = tp / float(npos)
        #print(rec)
        # print(type(rec))
        #perc=tp/(tp+fp)
        prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
        #?print(prec)
        # print(type(prec))
        ap = voc_ap(rec, prec, use_07_metric)
        #print(ap)
        if cls_name[cls_num] not in pr_data:
            pr_data.update({cls_name[cls_num]:[rec,prec,ap]})
    return pr_data #,mAP/7,np.array(mAP_rec/7),np.array(mAP_prec/7)

def voc_ap(rec, prec, use_07_metric):#由于use_07_metric=true时计算结果于实际更接近
    #计算ap,use_07_metric=true,# 2010年以前按recall等间隔取11个不同点处的精度值做平均(0., 0.1, 0.2, …, 0.9, 1.0)
    if use_07_metric:
        ap = 0.
        for t in np.arange(0., 1.1, 0.1):#([0.0,0.1,0.2,0.3,...,1.0])
            #print(11111111111111111111111111)
            if np.sum(rec >= t) == 0:
                p = 0
            else:
                p = np.max(prec[rec >= t])
            ap = ap + p / 11.
    #use_07_metric=false # 2010年以后取所有不同的recall对应的点处的精度值做平均
    else:
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
        i = np.where(mrec[1:] != mrec[:-1])[0]
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    return ap

def draw_pr(prediction_file,prediction_algorithm,ground_truth_file,cls,use_07_metric):

    #画多个算法多个类别的pr曲线
    MAP=[0, 0, 0, 0, 0, 0, 0]#用于统计map
    COLOR = ["#054E9F", "#FFA500", "#B0C4DE", "#008000", "#f6aad0", "#429ffd", "#435055"]
    for cls_name in cls:
        for i in range(len(prediction_file)):
            pr_data=get_pr_data("Prediction/"+prediction_file[i],"Ground_Truth/"+ground_truth_file[i],cls,use_07_metric[i])
            MAP[i]=MAP[i]+pr_data[cls_name][2]
            the_color = COLOR[i]
            plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i],color=the_color)
            title=cls_name+' PR Curve'
            plt.title(title)
            plt.xlabel('Recall')
            plt.ylabel('Precision')
            plt.ylim([0.0, 1.0])
            plt.xlim([0.0, 1.0])
            plt.grid(ls='-.')
            plt.legend()
        plt.savefig("Image_PR/"+title+'.png', dpi=600)
        # plt.show()
        plt.close() 

    #画各个算法map的pr曲线
    for i in range(len(prediction_file)): 
        pr_data_map=get_pr_data_map("Prediction/"+prediction_file[i],"Ground_Truth/"+ground_truth_file[i],cls,use_07_metric[i])
        the_color = COLOR[i]
        plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i],color=the_color)
        title='Precision-Recall Curve'
        plt.title(title)
        plt.xlabel('Recall')
        plt.ylabel('Precision')
        plt.ylim([0.0, 1.0])
        plt.xlim([0.0, 1.0])
        plt.grid(ls='-.')
        plt.legend()
    plt.savefig("Image_PR/"+title+'.png', dpi=600)
    plt.show()
    plt.close() 


# if __name__ == '__main__':
#     # -*- coding: UTF-8 -*-
#     import matplotlib.pyplot as plt
#     cls=['pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning_tricycle', 'bus', 'motor'] # 类别
#     # prediction_file=["FRCNN.txt", 'RetinaNet.txt', 'CornerNet.txt', 'CenterNet.txt', 'tridentnet.txt', 'ourResult.txt', 'SSD.txt'] # 放在Prediction里面"Faster_RCNN.txt",记得新建文件夹Prediction
#     # prediction_algorithm=["FRCNN", 'RetinaNet', 'CornerNet', 'CenterNet', 'tridentnet', 'ourResult', 'SSD'] # 对应上面的文件的算法名称
#     # use_07_metric=[False, False, False, False, False, False, False]
#     # ground_truth_file=["gt.txt", 'gt.txt', 'gt.txt', 'gt.txt', 'gt.txt', 'gt.txt', 'gt.txt']# 放在Ground Truth里面,记得新建文件夹Ground Truth
#     prediction_file=["FRCNN.txt", 'RetinaNet.txt', 'ourResult.txt', 'SSD.txt'] # 放在Prediction里面"Faster_RCNN.txt",记得新建文件夹Prediction
#     prediction_algorithm=["FRCNN", 'RetinaNet', 'ourResult', 'SSD'] # 对应上面的文件的算法名称
#     use_07_metric=[False, False, False, False]
#     ground_truth_file=["gt.txt", 'gt.txt', 'gt.txt', 'gt.txt']# 放在Ground Truth里面,记得新建文件夹Ground Truth

#     # 绘制出了各个类别的Precision-Recall曲线
#     draw_pr(prediction_file,prediction_algorithm,ground_truth_file,cls,use_07_metric)

froc.py

# -*- coding: UTF-8 -*-
#以faster和yolo为例
import numpy as np
import math
import matplotlib.pyplot as plt

def get_pr_data_map(prediction_file,ground_truth_file,cls_name,use_07_metric,ovthresh=0.5):
    with open(ground_truth_file, 'r') as f:####读取各个算法的gt.txt文件
        lines_gt = f.readlines()          #gt.txt的每一行,line_gt为一维数组
    with open(prediction_file, 'r') as f:####读取各个算法的pre.txt文件
        lines_pre = f.readlines()         #读取pre.txt的每一行,lines_gt为一维数组
            #根据txt文件中每一行的空格进行划分,splitlines_gt为二维数组,行为每一行的数据,列为每一行的数据划分
    splitlines_gt = [x.strip().split(' ') for x in lines_gt]
    #imagenames_gt为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到imagenames_gt中
    imagenames_gt = [ x[0] for x in splitlines_gt ] 
    #print(imagenames_gt)    
    class_recs = {}       
#     #BB_gt为二维数组,当第二列的类别与遍历的类别数相同时,将第二列之后的加入到BB_gt中
    BB_gt=np.array([[math.ceil(float(z)) for z in x[2:]] for x in splitlines_gt])
    for i in range(len(imagenames_gt)):
        #如果类别中没有该遍历的类别,则更新
        if imagenames_gt[i] not in class_recs:
            class_recs.update({imagenames_gt[i]:{"bbox":[],"det":[],"difficult":[]}})
        #否则将BB_gt[i]插入到类别框信息中
        class_recs[imagenames_gt[i]]["bbox"].append(BB_gt[i])
        class_recs[imagenames_gt[i]]["det"].append(False)
        class_recs[imagenames_gt[i]]["difficult"].append(False)
            #npos为imagenames_gt的长度
    npos=len(imagenames_gt)
    splitlines_pre = [x.strip().split(' ') for x in lines_pre] 
    #image_ids为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到image_ids中     
    image_ids = [x[0] for x in splitlines_pre] 
    #提取该类别预测框的置信度,当第二列的类别与遍历的类别数相同时,将第三列加入到confidence中
    confidence = np.array([float(x[2]) for x in splitlines_pre]) 
    #提取该类别预测框的bounging-boxes(二维数组),当第二列的类别与遍历的类别数相同时,将第三列之后的BBOX坐标插入
    BB_pre = np.array([[float(z) for z in x[3:]] for x in splitlines_pre]) 
    #按置信度大小将其索引从小到大排序(生成有顺序的一维数组)
    sorted_ind = np.argsort(-confidence)
    #按置信度大小将置信度从小到大排序(生成有顺序的一维数组)
    sorted_scores = np.sort(-confidence)
    #根据索引排序相应的bbox的坐标值(生成按置信度大小排列的二维数组)
    BB_pre = BB_pre[sorted_ind, :]
    #按置信度大小重新排列image_ids
    image_ids = [image_ids[x] for x in sorted_ind]
    nd = len(image_ids)
    tp = np.zeros(nd)
    fp = np.zeros(nd)
    pr_data_map=[]
    # print(nd)###############################################################################################################
    for d in range(nd):
        #按置信度顺序提取类别框
        #print(image_ids[d].get(image_ids[d]))
        # if class_recs[image_ids[d]] not in class_recs:
        # print(class_recs)
        if class_recs.get(image_ids[d]):
            #print(image_ids[d])
            R = class_recs[image_ids[d]]
            #print(R)
            bb = np.array(BB_pre[d, :]).astype(float)#按置信度顺序提取bounding box
            ovmax = -np.inf#ovmax为负无穷大的数
            BBGT = np.array(R['bbox']).astype(float)#按置信度顺序提取groudtruth bbox

            #计算iou
            if BBGT.size > 0:
                ixmin = np.maximum(BBGT[:, 0], bb[0])
                iymin = np.maximum(BBGT[:, 1], bb[1])
                ixmax = np.minimum(BBGT[:, 2], bb[2])
                iymax = np.minimum(BBGT[:, 3], bb[3])
                iw = np.maximum(ixmax - ixmin + 1., 0.)
                ih = np.maximum(iymax - iymin + 1., 0.)
                inters = iw * ih

                uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                       (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                       (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

                overlaps = inters / uni#重叠率
                ovmax = np.max(overlaps)#按重叠率的大小从大到小排序重叠率
                jmax = np.argmax(overlaps)#根据重叠率大小重新排序的索引

            if ovmax > ovthresh:#ovthresh=0.5阈值为0.5,判断tp和fp
                if not R['difficult'][jmax]:
                    if not R['det'][jmax]:
                        tp[d] = 1.
                        R['det'][jmax] = 1
                    else:
                        fp[d] = 1.
            else:
                fp[d] = 1.
        else:
            #print("*************************************************************"+str(d))
            fp[d]=1.


        
    fp = np.cumsum(fp)
    tp = np.cumsum(tp)
    #rec=tp/正样本数
    rec = tp / float(npos)
    # print(len(rec))
    # print(type(rec))
    #perc=tp/(tp+fp)
    prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
    # print(len(prec))
    fps = fp / npos
    # print(fps, prec, nd)
    # print(type(prec))
    ap = voc_ap(rec, prec, use_07_metric)
    print(ap)
    ###################################################
    
    # mAP_rec+=rec
    # print("mAP_rec:"+str(mAP_rec)+"\n")
    # mAP_prec+=prec
    # print("mAP_prec:"+str(mAP_prec)+"\n")
    # mAP+=ap
    # print("mAP:"+str(mAP)+"\n")
    ###################################################
    # if not pr_data.has_key(cls_name[cls_num]):
    # rec=np.array(rec)
    # prec=np.array(prec)
    # ap=np.array(ap)
    pr_data_map=np.array([fps.tolist(), rec.tolist()])#,ap.tolist()]
    pr_data_map=pr_data_map.tolist()

    #print(pr_data_map)
    return pr_data_map 


def get_pr_data(prediction_file,ground_truth_file,cls_name,use_07_metric,ovthresh=0.5):
    with open(ground_truth_file, 'r') as f:####读取各个算法的gt.txt文件
        lines_gt = f.readlines()          #gt.txt的每一行,line_gt为一维数组
    with open(prediction_file, 'r') as f:####读取各个算法的pre.txt文件
        lines_pre = f.readlines()         #读取pre.txt的每一行,lines_gt为一维数组

    pr_data={}

    for cls_num in range(len(cls_name)): #遍历每个类别数
    #ground_truth  
    	#根据txt文件中每一行的空格进行划分,splitlines_gt为二维数组,行为每一行的数据,列为每一行的数据划分
        splitlines_gt = [x.strip().split(' ') for x in lines_gt]
        #imagenames_gt为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到imagenames_gt中
        imagenames_gt = [ x[0] for x in splitlines_gt if int(x[1])==cls_num] 
        #print(imagenames_gt)           

        #BB_gt为二维数组,当第二列的类别与遍历的类别数相同时,将第二列之后的加入到BB_gt中
        BB_gt=np.array([[math.ceil(float(z)) for z in x[2:]] for x in splitlines_gt if int(x[1])==cls_num])
        #创建class_recs数组
        class_recs = {}
        for i in range(len(imagenames_gt)):
            #如果类别中没有该遍历的类别,则更新
            if imagenames_gt[i] not in class_recs:
                class_recs.update({imagenames_gt[i]:{"bbox":[],"det":[],"difficult":[]}})
            #否则将BB_gt[i]插入到类别框信息中
            class_recs[imagenames_gt[i]]["bbox"].append(BB_gt[i])
            class_recs[imagenames_gt[i]]["det"].append(False)
            class_recs[imagenames_gt[i]]["difficult"].append(False)
            #print(class_recs[imagenames_gt[i]])
        #npos为imagenames_gt的长度
        npos=len(imagenames_gt)
    
    #prediction 
    	#对预测框的每一行根据空格划分,splitlines_pre为二维数组   
        splitlines_pre = [x.strip().split(' ') for x in lines_pre] 
        #image_ids为一维数组,当第二列的类别与遍历的类别数相同时,将第一列加入到image_ids中     
        image_ids = [x[0] for x in splitlines_pre if int(x[1])==cls_num] 
		#提取该类别预测框的置信度,当第二列的类别与遍历的类别数相同时,将第三列加入到confidence中
        confidence = np.array([float(x[2]) for x in splitlines_pre if int(x[1])==cls_num]) 
        #提取该类别预测框的bounging-boxes(二维数组),当第二列的类别与遍历的类别数相同时,将第三列之后的BBOX坐标插入
        BB_pre = np.array([[float(z) for z in x[3:]] for x in splitlines_pre if int(x[1])==cls_num]) 
        #按置信度大小将其索引从小到大排序(生成有顺序的一维数组)
        sorted_ind = np.argsort(-confidence)
        #按置信度大小将置信度从小到大排序(生成有顺序的一维数组)
        sorted_scores = np.sort(-confidence)
        #根据索引排序相应的bbox的坐标值(生成按置信度大小排列的二维数组)
        BB_pre = BB_pre[sorted_ind, :]
        #按置信度大小重新排列image_ids
        image_ids = [image_ids[x] for x in sorted_ind]
        #该类别的预测框的数量
        nd = len(image_ids)
        tp = np.zeros(nd)#将长度为nd数组置0
        fp = np.zeros(nd)

        # print(nd)###############################################################################################################
        for d in range(nd):
        	#按置信度顺序提取类别框
        	#print(image_ids[d].get(image_ids[d]))
            # if class_recs[image_ids[d]] not in class_recs:
            if class_recs.get(image_ids[d]):
                #print(image_ids[d])
                R = class_recs[image_ids[d]]
                #print(R)
                bb = np.array(BB_pre[d, :]).astype(float)#按置信度顺序提取bounding box
                ovmax = -np.inf#ovmax为负无穷大的数
                BBGT = np.array(R['bbox']).astype(float)#按置信度顺序提取groudtruth bbox

	            #计算iou
                if BBGT.size > 0:
                    ixmin = np.maximum(BBGT[:, 0], bb[0])
                    iymin = np.maximum(BBGT[:, 1], bb[1])
                    ixmax = np.minimum(BBGT[:, 2], bb[2])
                    iymax = np.minimum(BBGT[:, 3], bb[3])
                    iw = np.maximum(ixmax - ixmin + 1., 0.)
                    ih = np.maximum(iymax - iymin + 1., 0.)
                    inters = iw * ih

                    uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                           (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                           (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

                    overlaps = inters / uni#重叠率
                    ovmax = np.max(overlaps)#按重叠率的大小从大到小排序重叠率
                    jmax = np.argmax(overlaps)#根据重叠率大小重新排序的索引

                if ovmax > ovthresh:#ovthresh=0.5阈值为0.5,判断tp和fp
                    if not R['difficult'][jmax]:
                        if not R['det'][jmax]:
                            tp[d] = 1.
                            R['det'][jmax] = 1
                        else:
                            fp[d] = 1.
                else:
                    fp[d] = 1.
            else:
                #print("*************************************************************"+str(d))
                fp[d]=1.


            
        fp = np.cumsum(fp)
        tp = np.cumsum(tp)
        #rec=tp/正样本数
        rec = tp / float(npos)
        #print(rec)
        # print(type(rec))
        #perc=tp/(tp+fp)
        prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
        #?print(prec)
        # print(type(prec))
        ap = voc_ap(rec, prec, use_07_metric)
        #print(ap)
        ###################################################
        fps = fp / npos
        
        # mAP_rec+=rec
        # print("mAP_rec:"+str(mAP_rec)+"\n")
        # mAP_prec+=prec
        # print("mAP_prec:"+str(mAP_prec)+"\n")
        # mAP+=ap
        # print("mAP:"+str(mAP)+"\n")
        ###################################################
        if cls_name[cls_num] not in pr_data:
            pr_data.update({cls_name[cls_num]:[fps,rec,ap]})
    return pr_data #,mAP/7,np.array(mAP_rec/7),np.array(mAP_prec/7)

def voc_ap(rec, prec, use_07_metric):#由于use_07_metric=true时计算结果于实际更接近
    #计算ap,use_07_metric=true,# 2010年以前按recall等间隔取11个不同点处的精度值做平均(0., 0.1, 0.2, …, 0.9, 1.0)
    if use_07_metric:
        ap = 0.
        for t in np.arange(0., 1.1, 0.1):#([0.0,0.1,0.2,0.3,...,1.0])
            #print(11111111111111111111111111)
            if np.sum(rec >= t) == 0:
                p = 0
            else:
                p = np.max(prec[rec >= t])
            ap = ap + p / 11.
    #use_07_metric=false # 2010年以后取所有不同的recall对应的点处的精度值做平均
    else:
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
        i = np.where(mrec[1:] != mrec[:-1])[0]
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    return ap

def draw_pr(prediction_file,prediction_algorithm,ground_truth_file,cls,use_07_metric):
    # for i in range(len(prediction_file)):
    #     pr_data=get_pr_data("Prediction/"+prediction_file[i],"Ground_Truth/"+ground_truth_file,cls)
    #     for cls_name in pr_data:
    #         plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' mAP='+str(round(pr_data[cls_name][2],3)))
    #         title='PR Curve of '+cls_name
    #         plt.title(title)
    #         plt.xlabel('Recall')
    #         plt.ylabel('Precision')
    #         plt.ylim([0.0, 1.0])
    #         plt.xlim([0.0, 1.0])
    #         plt.grid(ls='-.')
    #         plt.legend()
    #         plt.savefig("Images/"+title+'.png', dpi=300)
    #         plt.show()
    #         plt.close()
    # for i in range(len(prediction_file)):
    #     pr_data=get_pr_data("Prediction/"+prediction_file[i],"Ground_Truth/"+ground_truth_file,cls)

    #画多个算法多个类别的pr曲线
    MAP=[0,0,0,0,0,0]#用于统计map
    for cls_name in cls:
        for i in range(len(prediction_file)):
            pr_data=get_pr_data("Prediction/"+prediction_file[i],"Ground_Truth/"+ground_truth_file[i],cls,use_07_metric[i])
            MAP[i]=MAP[i]+pr_data[cls_name][2]
            # print(pr_data)

            if i==0:
                plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' AP='+str(round(pr_data[cls_name][2],3)),color="#054E9F")
            elif i==1:
                plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' AP='+str(round(pr_data[cls_name][2],3)),color="#FFA500")
            elif i==2:
                plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' AP='+str(round(pr_data[cls_name][2],3)),color="#B0C4DE")
            elif i==3:
                plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' AP='+str(round(pr_data[cls_name][2],3)),color="#008000")
            elif i==4:
                plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' AP='+str(round(pr_data[cls_name][2],3)),color="#BA55D3")
            elif i==5:
                plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' AP='+str(round(pr_data[cls_name][2],3)),color="#FF0000")
            # plt.plot(pr_data[cls_name][0],pr_data[cls_name][1],label=prediction_algorithm[i]+' AP='+str(round(pr_data[cls_name][2],3)),color="#054E9F")
            title=cls_name+' FROC Curve'
            plt.title(title,fontsize=15)
            plt.xlabel('False Positive Per Scan',fontsize=15)
            plt.ylabel('Sensitive',fontsize=15)
            plt.ylim([0.0, 1.0])
            plt.xlim([0.0, 10])
            plt.grid(ls='-.')
            plt.legend()
            plt.savefig("Image_PR/"+title+'.png', dpi=600)
            print("save....ok!!!")
        plt.show()
        plt.close() 

    #画各个算法map的pr曲线
    for i in range(len(prediction_file)): 
        pr_data_map=get_pr_data_map("Prediction/"+prediction_file[i],"Ground_Truth/"+ground_truth_file[i],cls,use_07_metric[i])
        if i==0:
            plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i]+' mAP='+str(round(MAP[i]/len(cls),3)),color="#054E9F")
        elif i==1:
            plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i]+' mAP='+str(round(MAP[i]/len(cls),3)),color="#FFA500")
        elif i==2:
            plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i]+' mAP='+str(round(MAP[i]/len(cls),3)),color="#B0C4DE")
        elif i==3:
            plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i]+' mAP='+str(round(MAP[i]/len(cls),3)),color="#008000")
        elif i==4:
            plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i]+' mAP='+str(round(MAP[i]/len(cls),3)),color="#BA55D3")
        elif i==5:
            plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i]+' mAP='+str(round(MAP[i]/len(cls),3)),color="#FF0000")
        #plt.plot(pr_data_map[0],pr_data_map[1],label=prediction_algorithm[i]+' mAP='+str(round(MAP[i]/len(cls),3)),color="#054E9F")
        title='FROC Curve'
        plt.title(title,fontsize=15)
        plt.xlabel('False Positive Per Scan',fontsize=15)
        plt.ylabel('Sensitive',fontsize=15)
        plt.ylim([0.0, 1.0])
        plt.xlim([0.0, 10])
        plt.grid(ls='-.')
        plt.legend()
        plt.savefig("Image_PR/"+title+'.png', dpi=600)
        print("save....ok!!!")
    plt.show()
    plt.close() 


 
相关标签: 工具代码

上一篇: 获取图片宽、高

下一篇: 插入排序