c++实现 CPU nms算法

自测好用的C++实现的NMS算法片段,一看就能回忆起原理。本次整理原理加上手撸代码共花费2个小时,这大概是我第三次全流程撸nms算法吧,希望以后再来撸它的时候效率能大大提高。

对一组bounding boxes进行nms,输入iou阈值去除重复的目标框,经过nms算法后返回实际的目标框
计算IOU的时候bbox的坐标加上分类id乘以一个经验值,将不同分类id的bbox离散到不同的数据域做IOU,避免了数据的拷贝,提升算法性能。

std::vector<Bbox> nms(std::vector<Bbox>&boxes, float threshold)
{
	int wh_max = 7680;
	std::vector<Bbox> resluts;
	std::sort(boxes.begin(), boxes.end(), sort_confidence);
	while (boxes.size() > 0)
	{
		//最上面的框肯定是要放到结果中的,因为它的置信度最大,要删也是删置信度小的框	
		resluts.push_back(boxes[0]);
		int index = 1;
		while (index < boxes.size()) {
			//目标框坐标按分类id分簇,因为做IOU的时候只对分类id相同的框进行比较
			float aleft = boxes[0].left + boxes[0].clas * wh_max;
			float atop = boxes[0].top + boxes[0].clas * wh_max;
			float aright =  boxes[0].right + boxes[0].clas * wh_max;
			float abottom = boxes[0].bottom + boxes[0].clas * wh_max;

			float bleft = boxes[index].left + boxes[index].clas * wh_max;
			float btop = boxes[index].top + boxes[index].clas * wh_max;
			float bright = boxes[index].right + boxes[index].clas * wh_max;
			float bbottom = boxes[index].bottom + boxes[index].clas * wh_max;
			
			float iou_value = iou(aleft, atop, aright, abottom,
					bleft, btop, bright, bbottom);
			if (iou_value > threshold) {
				//IOU大于阈值时,删除遍历的框,删除后index刚好指向下一个遍历的框,巧妙
				boxes.erase(boxes.begin() + index);
			}
			else {
				//不删,那就继续遍历下一个框
				index++;
			}
		}
		//当前置信度最高的框,和其他目标框遍历比较结束,最后删除它
		boxes.erase(boxes.begin());
	}
	return  resluts;
}

输入NMS算法的数据首先要根据置信度阈值从大到小排序:
CPU实现可以用std::sort实现

//std::sort的函数定义
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

Compare参数是一个用来比较元素大小的函数或者函数对象。它接受两个元素作为参数,返回一个布尔值,表示第一个元素是否应该排在第二个元素之前如果没有提供Compare参数,默认non-descending(从小到大)排序。

此处我们需要提供一个从大到小排序的Compare函数对象。

bool sort_confidence(Bbox bbox1,Bbox bbox2)
{
	return bbox1.confidence > bbox2.confidence ? true : false;
}

Compare函数在nms中使用:

std::sort(boxes.begin(), boxes.end(), sort_confidence);

iou算法使用的函数,记录一下这次自己手写的:

//IOU算法, 输入两个box坐标,计算交并比
float intersection_over_union(Bbox box1, Bbox box2)
{
    float _bottom = std::fmin(box1.bottom, box2.bottom);
    float _top = std::fmax(box1.top, box2.top);
    float _right = std::fmin(box1.right, box2.right);
    float _left = std::fmax(box2.left,box2.left);
    float inter_area = std::fmax(_bottom-_top, 0.0) * std::fmax(_right-_left, 0.0);
    if(inter_area == 0.0)
        return 0.0;

    float union_area = std::fmax(bbox1.bottom - bbox1.top, 0.0) * std::fmax(bbox1.right - bbox1.top, 0.0) + /
    std::fmax(bbox1.bottom - bbox1.top, 0.0) * std::fmax(bbox1.right - bbox1.top, 0.0) - inter_area;

    return inter_area / union_area;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值