目标检测AP计算(C++)

本文记录计算目标检测AP(average precision) 的方法和c++实现

目标检测的输出也就是AP计算的输入

//  每张测图有多个目标物体
std::vector<std::vector<cv::RotatedRect>> pred_bbox;  // predicted rotated bbox 
std::vector<std::vector<float>> pred_score;           // prediction score
std::vector<std::vector<cv::RotatedRect>> gt_bbox;    // ground truth object rotated bbox

assert(pred_rbox.size() == pred_score.size())

计算过程

先计算得到precision和recall (也就是得到PR曲线)

void CalcPRCurve(float thresh_val, const std::vector<std::vector<cv::RotatedRect>>& pred_bbox, const std::vector<std::vector<float>>& pred_score, const std::vector<std::vector<cv::RotatedRect>>& gt_bbox, std::vector<float>& precision, std::vector<float>& recall)
{
    assert(!pred_bbox.empty());
    assert(!pred_score.empty());
    assert(!gt_bbox.empty());
    assert(pred_bbox.size() == pred_score.size());
    assert(pred_score.size() == gt_bbox.size());

	precision = std::vector<float>();
	recall = std::vector<float>();
    
    // Step 1. Check each prediction positive or negative
	std::vector<float> pred_score_all;
	std::vector<int> positive_flag;
	int gt_num = 0;
	for (int i = 0; i < pred_bbox.size(); ++i) {
		if (pred_score[i].size() != pred_bbox[i].size()) {
			std::cerr << i << "-th image prediction input dimension wrong.\n";
			return 0;
		}

		std::vector<bool> gt_bbox_check_flags(gt_bbox.size(), true);
		for (int j = 0; j < pred_bbox[i].size(); ++j) {
			pred_score_all.push_back(pred_score[i][j]);
			positive_flag.push_back(IsPositive(thresh_val, pred_bbox[i][j], gt_bbox[i], gt_bbox_check_flags));
		}

		gt_num += gt_bbox[i].size();
	}
	
	// Step 2. Sort predictions by score from high to low
	SortByScore(pred_score_all, positive_flag);
    
    // Step 3. Calculate precision and recall
	int positive_cnt = 0;
	for (int i = 0; i < pred_score_all.size(); ++i) {
		if (positive_flag[i]) {
			positive_cnt++;
		}
		precision.push_back(float(positive_cnt) / float(i + 1));
		recall.push_back(float(positive_cnt) / float(gt_num));
	}
}

其中,判断检测物是否为真,以及排序的实现如下:

// A prediction is positive if IoU ≥ thresh_val
// If multiple detections of the same object are detected, it counts the first one (highest score) as positive while the rest as negative.
int IsPositive(float thresh_val, const cv::RotatedRect& rrt, const std::vector<cv::RotatedRect>& gt_bbox, std::vector<bool>& gt_bbox_check_flags)
{
    assert(gt_bbox.size() == gt_bbox_check_flags.size());

	for (int i = 0; i < gt_bbox.size(); ++i) {
		if (!gt_bbox_check_flags[i]) { continue; }

		const cv::RotatedRect&gt = gt_bbox[i];
		cv::Mat intersect_region;
		if (cv::rotatedRectangleIntersection(gt, rrt, intersect_region) >= 1) {
			float area = cv::contourArea(intersect_region);
			float gt_area = gt.size.area();
			float pred_area = rrt.size.area();
			float IoU = area / (gt_area + pred_area - area);

			if (IoU >= thresh_val) { 
				gt_bbox_check_flags[i] = false;
				return 1; 
			}				
		}
	}

	return 0;
}

// Sort both pred_score_all and positive_flag by pred_score_all
void SortByScore(std::vector<float>& pred_score_all, std::vector<int>& positive_flag)
{
	assert(pred_score_all.size() == positive_flag.size());

	std::vector<std::pair<float, int>> pairs;
	for (size_t i = 0; i < pred_score_all.size(); ++i) {
		pairs.push_back(std::make_pair(pred_score_all[i], positive_flag[i]));
	}

	// Sort the combined vector in descending order of scores
	std::sort(pairs.begin(), pairs.end(), [](const std::pair<float, int>& a, const std::pair<float, int>& b) { return a.first > b.first; });

	// Separate the sorted scores and flags back into separate vectors
	for (size_t i = 0; i < pairs.size(); ++i) {
		pred_score_all[i] = pairs[i].first;
		positive_flag[i] = pairs[i].second;
	}
}

最后计算AP

// Area Under Curve (AUC) method
float CalcAP(const std::vector<float>& precision, const std::vector<float>& recall)
{
	assert(!precision.empty());
    assert(!recall.empty()); 
    assert(precision.size() == recall.size());
	
	float last_r = 0;
	float auc = 0;
	for (int i = 1; i < precision.size(); ++i) {
		if (precision[i] < precision[i-1]) {
			auc += (recall[i - 1] - last_r) * precision[i - 1];
			last_r = recall[i - 1];
		}
	}
	auc += (recall.back() - last_r)*precision.back();
	return auc * 100; // in percentage
}

计算mAP

上述实现针对一个类别的物体检测的AP值,当有多个类别(n个),则针对每个类别的检测结果,用上述方法计算一个对应的AP值,然后求n个AP值得平均

计算AP50, AP75

AP50, AP75以及类似指标,是指AP值分别对应IoU计算的threshold = 0.5 和0.75 的情况,可以修改CalcPRCurve的第一个参数thresh_val,设为0.5.0.75,计算相应的AP即可

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值