#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class Box{
public:
int x1, x2, y1, y2; // 左上坐标(x1,y1), 右下坐标(x2,y2) x2 > x1 、 y2 > y1
float score;
};
// 计算iou:两个边界框的交并比
float iou(Box a, Box b){
int x1 = max(a.x1, b.x1);
int x2 = min(a.x2, b.x2);
int y1 = max(a.y1, b.y1);
int y2 = min(a.y2, b.y2);
int w = max(0, x2 - x1); // 如果没有交集,x2 < x1 则边长取0
int l = max(0, y2 - y1);
int s3 = w * l;
int s1 = (a.x2 - a.x1) * (a.y2 - a.y1);
int s2 = (b.x2 - b.x1) * (b.y2 - b.y1);
if(((s1 + s2 - s3)) == 0) return; // 排除分母为0
return static_cast<float>(s3 / (s1 + s2 - s3));
}
// 计算nms 选择分数最高的目标框,和其他的比较iou大小
// 如果iou>thr(阈值),remove
bool compare(Box a, Box b){
return a.score > b.score;
}
vector<Box> nms(vector<Box> Box_set, float thr){
vector<Box> res;
sort(Box_set.begin(), Box_set.end(), compare); // 将目标框集合按照分数从大到小排序
res.push_back(Box_set[0]); // 将分数最大的保存进结果
Box temp = Box_set[0];
while(Box_set.size() > 1){
res.emplace_back(Box_set.begin()); // 将分数最大的存进结果,使用Push_Back()会报错?
int index = 1;
while(Box_set.size() > 1){
float iou = iou(Box_set[0], Box_set[index]); // 计算分数最大的目标框和其他目标框的iou
if(iou > thr){
Box_set.erase(Box_set.begin() + index); // 如果iou大于阈值,删除这个目标框, 保留分数最大的目标框
} // erase()函数会改变容器的大小,相当于后面的目标框向容器自动前面进1,所以index不用++
else{
index++;
}
}
Box_set.erase(Box_set.begin()); // 删除已经保存进结果的目标框
}
res.erase(res.begin()); // 最后结果不止一个目标框,一定有分数最大的目标框
return res;
}
参考