目标检测检测精度介绍和代码计算 python

在一个数据集检测中,会产生四类检测结果:TP、TN 、FP 、FN:

T(True):最终预测结果正确。

F(False):最后预测结果错误。

P(Positive):模型预测其是正样本(目标本身是,模型也预测它是)。

N(Negative):模型预测其是负样本(目标本身是,但模型预测它是个)。

TP:样本的真实类别是正样本(P),并且模型预测的结果也是正样本(P),预测正确(T)(目标本身是,模型也预测它是,预测正确)。

TN:样本的真实类别是负样本(N),并且模型将其预测成为负样本(N),预测正确(T)(目标本身不是,模型预测它不是,是个其他的东西,预测正确)。

FP:样本的真实类别是负样本(N),但是模型将其预测成为正样本(P),预测错误(F)(目标本身不是,模型预测它是,预测错误)。

FN:样本的真实类别是正样本(P),但是模型将其预测成为负样本(N),预测错误(F)(目标本身是,模型预测它不是,是个其他的东西,预测错误)。


TP+FP+TN+FN:样本总数。
TP+FN:实际正样本数。
TP+FP:预测结果为正样本的总数,包括预测正确的和错误的。
FP+TN:实际负样本数。
TN+FN:预测结果为负样本的总数,包括预测正确的和错误的

1. 召回率(Recall):

表示的是样本中的正例有多少被预测正确了(找得全)所有正例中被正确预测出来的比例。Recall=\frac{\frac{TP}{}}{TP+FN}

举个栗子:现有100只动物,分别是30只猫50只狗20只猪。经过模型检测之后结果表示只有25只猫,或许它把另外5只猫错认成狗和猪了吧,,那么召回率Recall(猫)= 25/30 = 83%

注:召回率越高,实际为正样本(P)被预测出来的概率越高,类似于“宁可错杀一千,绝不放过一个”。

2. 精确率(Precision):

表示的是预测为正的样本中有多少是真正的正样本(找得对)。预测结果中真正的正例的比例。Precision=\frac{TP}{TP+FP}

举个栗子:现有100只动物,分别是30只猫50只狗20只猪。经过模型检测之后结果表示有35只猫,但它认为的35只猫里面有2只狗3只猪,所以猫预测对的只有30只,那么精确率Precision(猫)= 30/35 = 85.7%

3. 准确率(Accuracy):

模型判断正确的数据(TP+TN)占总数据的比例
Acc=\frac{TP+TN}{TP+TN+FP+FN}

举个栗子:现有100只动物,分别是30只猫50只狗20只猪。经过模型检测之后预测正确的是20只猫30只狗10只猪,那么准确率(Accuracy)=(20+30+10)/100 = 60%。

注:通常来说正确率越高,模型越好。

Accuracy度量的是全局样本预测情况。而对于Precision和Recall而言,每个类都需要单独计算其Precision和Recall

4. 漏检率:

反映分类器或者模型正确预测负样本纯度的能力,减少将正样本预测为负样本,即正样本被预测为负样本占总的正样本的比例。值越小,性能越好。

漏报率是衡量模型在正例中错误地预测为负例的能力。它表示实际为正例的样本中被错误预测为负例的比例。漏报率低表示模型在正例预测方面的性能较好。

FNR=\frac{FN}{TP+FN}

5. 误检率:

反映分类器或者模型正确预测正样本纯度的能力,减少将负样本预测为正样本,即负样本被预测为正样本占总的负样本的比例。值越小,性能越好。

 误报率是衡量模型在负例中错误地预测为正例的能力。它表示实际为负例的样本中被错误预测为正例的比例。误报率低表示模型在负例预测方面的性能较好。

FPR=\frac{FP}{FP+TN}

计算代码

import os

def calculate_iou(box1, box2):
    x1 = max(box1[0], box2[0])
    y1 = max(box1[1], box2[1])
    x2 = min(box1[0] + box1[2], box2[0] + box2[2])
    y2 = min(box1[1] + box1[3], box2[1] + box2[3])

    intersection = max(0, x2 - x1) * max(0, y2 - y1)
    area1 = box1[2] * box1[3]
    area2 = box2[2] * box2[3]
    union = area1 + area2 - intersection

    iou = intersection / union
    return iou

def calculate_metrics(ground_truth_boxes, detected_boxes):
    true_positives = 0  #真正例,预测为正例而且实际上也是正例;
    false_negatives = 0 #假负例,预测为负例然而实际上却是正例;
    false_positives = 0 #假正例,预测为正例然而实际上却是负例;
    true_negatives = 0  # 真负例,预测为负例而且实际上也是负例。目标检测默认为0 

    # 遍历每个真实框
    for truth_box in ground_truth_boxes:
        found_match = False
        # 遍历每个检测到的框
        for detected_box in detected_boxes:
            iou = calculate_iou(truth_box, detected_box) # 计算真实框和检测框的交并比
            if iou >= 0.5 and truth_box[4] == detected_box[4]:  # 如果交并比大于等于0.5且类别匹配
                true_positives += 1 # 则增加真正例计数
                found_match = True
                break
        if not found_match:
            false_negatives += 1  # 如果未找到匹配的检测框,则增加假负例计数

    unique_detected_classes = set(box[4] for box in detected_boxes) # 获取检测到的框中的唯一类别
    unique_ground_truth_classes = set(box[4] for box in ground_truth_boxes) # 获取真实框中的唯一类别

    for c in unique_detected_classes:
        if c not in unique_ground_truth_classes:
            false_positives += sum(box[4] == c for box in detected_boxes) # 计算假正例

    for c in unique_ground_truth_classes:
        if c not in unique_detected_classes:
            false_negatives += sum(box[4] == c for box in ground_truth_boxes)  # 根据未检测到的类别,增加假负例的计数

    total_instances = true_positives + false_negatives + false_positives + true_negatives
    accuracy = (true_positives + true_negatives) / total_instances if total_instances > 0 else 0 # 准确率计算
    recall = true_positives / (true_positives + false_negatives) if (true_positives + false_negatives) > 0 else 0 # 召回率计算
    precision = true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0 # 精确率计算
    miss_rate = false_negatives / (false_negatives + true_positives) if (false_negatives + true_positives) > 0 else 0 # 漏检率计算
    false_positive_rate = false_positives / (false_positives + true_negatives) if (false_positives + true_negatives) > 0 else 0 # 误检率计算

    return recall, miss_rate, false_positive_rate, precision, accuracy

def read_boxes_from_txt(file_path):
    boxes = []
    with open(file_path, 'r') as file:
        for line in file:
            values = line.strip().split()
            box = [float(values[1]), float(values[2]), float(values[3]), float(values[4]), values[0]]
            boxes.append(box)
    return boxes

# 文件夹路径
ground_truth_folder = 'your/path'  # 替换为实际的文件夹路径
detected_folder = 'your/path'  # 替换为实际的文件夹路径

# 计算目标检测指标
total_recall = 0
total_miss_rate = 0
total_false_positive_rate = 0
total_precision = 0
total_accuracy = 0
num_images = 0

for filename in os.listdir(ground_truth_folder):
    if filename.endswith(".txt"):
        ground_truth_boxes = read_boxes_from_txt(os.path.join(ground_truth_folder, filename))
        detected_boxes = read_boxes_from_txt(os.path.join(detected_folder, filename))

        recall, miss_rate, false_positive_rate, precision, accuracy = calculate_metrics(ground_truth_boxes, detected_boxes)

        total_recall += recall
        total_miss_rate += miss_rate
        total_false_positive_rate += false_positive_rate
        total_precision += precision
        total_accuracy += accuracy
        num_images += 1

average_recall = total_recall / num_images
average_miss_rate = total_miss_rate / num_images
average_false_positive_rate = total_false_positive_rate / num_images
average_precision = total_precision / num_images
average_accuracy = total_accuracy / num_images

print("Average Recall: ", average_recall)
print("Average Miss Rate: ", average_miss_rate)
print("Average False Positive Rate: ", average_false_positive_rate)
print("Average Precision: ", average_precision)
print("Average Accuracy: ", average_accuracy)


import os


def calculate_iou(box1, box2):
    x1 = max(box1[0], box2[0])
    y1 = max(box1[1], box2[1])
    x2 = min(box1[0] + box1[2], box2[0] + box2[2])
    y2 = min(box1[1] + box1[3], box2[1] + box2[3])

    intersection = max(0, x2 - x1) * max(0, y2 - y1)
    area1 = box1[2] * box1[3]
    area2 = box2[2] * box2[3]
    union = area1 + area2 - intersection

    iou = intersection / union
    return iou


def calculate_metrics(ground_truth_boxes, detected_boxes, class_id):
    """

    :param ground_truth_boxes:
    :param detected_boxes:
    :param class_id:
    :return:
    """
    true_positives = 0  # 真正例,预测为正例而且实际上也是正例;
    false_negatives = 0  # 假负例,预测为负例然而实际上却是正例;
    false_positives = 0  # 假正例,预测为正例然而实际上却是负例;
    true_negatives = 0  # 真负例,预测为负例而且实际上也是负例。

    # 遍历每个真实框
    for truth_box in ground_truth_boxes:
        found_match = False
        # 遍历每个检测到的框
        for detected_box in detected_boxes:
            iou = calculate_iou(truth_box, detected_box)  # 计算真实框和检测框的交并比
            if iou >= 0.5 and truth_box[4] == detected_box[4] == class_id:  # 如果交并比大于等于0.5且类别匹配
                true_positives += 1  # 则增加真正例计数
                found_match = True
                break
        if not found_match and truth_box[4] == class_id:
            false_negatives += 1  # 如果未找到匹配的检测框,则增加假负例计数

    for detected_box in detected_boxes:  # 它的类别与 class_id 不匹配,并且它与所有真实框的类别都不匹配,则将其视为真负例
        if detected_box[4] != class_id:
            if all(detected_box[4] != box[4] for box in ground_truth_boxes):
                true_negatives += 1  # 根据未匹配的检测框增加真负例计数

    for detected_box in detected_boxes:  # 其类别与 class_id 匹配,但与所有真实框的类别都不匹配,则将其视为假正例
        if detected_box[4] == class_id:
            if all(detected_box[4] != box[4] for box in ground_truth_boxes):
                false_positives += 1  # 根据未匹配的检测框增加假正例计数

    return true_positives, false_positives, false_negatives, true_negatives


def read_boxes_from_txt(file_path):
    boxes = []
    with open(file_path, 'r') as file:
        for line in file:
            values = line.strip().split()
            box = [float(values[1]), float(values[2]), float(values[3]), float(values[4]), values[0]]
            boxes.append(box)
    return boxes


# 文件夹路径
ground_truth_folder = 'labels'  # 标注标签
detected_folder = 'labels_detector'  # 检测标签
# 获得真实标签文件和检测文件的列表
ground_truth_files = set(os.listdir(ground_truth_folder))
detected_files = set(os.listdir(detected_folder))

# 遍历所有的文件
all_files = ground_truth_files.union(detected_files)

total_TP = 0  # 真正例,预测为正例而且实际上也是正例;
total_FP = 0  # 假正例,预测为正例然而实际上却是负例;
total_FN = 0  # 假负例,预测为负例然而实际上却是正例;
total_TN = 0
# 遍历每个真实框
#"car", "lightTruck","person","tipperTruck","construction","tricycle", "train","bicycle"
class_id = '0'
#for filename in os.listdir(ground_truth_folder):
for filename in all_files:
    if filename.endswith(".txt"):
        ground_truth_path = os.path.join(ground_truth_folder, filename)
        detected_path = os.path.join(detected_folder, filename)
        ground_truth_boxes = read_boxes_from_txt(ground_truth_path) if os.path.exists(ground_truth_path) else []
        detected_boxes = read_boxes_from_txt(detected_path) if os.path.exists(detected_path) else []

        # recall, miss_rate, false_positive_rate, precision, accuracy = calculate_metrics(ground_truth_boxes, detected_boxes)
        TP, FP, FN, TN = calculate_metrics(ground_truth_boxes, detected_boxes, class_id)

        total_TP += TP
        total_FP += FP
        total_FN += FN
        total_TN += TN

# 计算准确率、召回率、精确率、漏检率和误检率
total_instances = total_TP + total_FN + total_FP + total_TN
accuracy = (total_TP+total_TN) / total_instances if total_instances > 0 else 0
recall = total_TP / (total_TP + total_FN) if (total_TP + total_FN) > 0 else 0
precision = total_TP / (total_TP + total_FP) if (total_TP + total_FP) > 0 else 0
miss_rate = total_FN / (total_FN + total_TP) if (total_FN + total_TP) > 0 else 0
false_positive_rate = total_FP / (total_FP + total_TN) if (total_FP + total_TN) > 0 else 0

print("Average Recall: ", recall)  # 召回率
print("Average Precision: ", precision)  # 精确率
print("Average Accuracy: ", accuracy)  # 准确率
print("Average Miss Rate: ", miss_rate)  # 漏检率
print("Average False Positive Rate: ", false_positive_rate)  # 误检率

  • 26
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值