问题:
最近做目标检测的时候,发现通过极大值,还是有可能出现两个重叠的方框
具体如下:
核心代码如下:
static void nms_sorted_bboxes(const std::vector<ObjectDef>& faceObjectDefs, std::vector<int>& picked,
float nms_threshold) {
picked.clear();
const int n = faceObjectDefs.size();
std::vector<float> areas(n);
for (int i = 0; i < n; i++) {
areas[i] = faceObjectDefs[i].bbox.rect.area();
}
for (int i = 0; i < n; i++) {
const ObjectDef& a = faceObjectDefs[i];
int keep = 1;
for (int j = 0; j < (int)picked.size(); j++) {
const ObjectDef& b = faceObjectDefs[picked[j]];
// intersection over union
float inter_area = intersection_area(a, b);
float union_area = areas[i] + areas[picked[j]] - inter_area;
// float IoU = inter_area / union_area
if (inter_area / union_area > nms_threshold)
keep = 0;
}
if (keep)
picked.push_back(i);
}
}
问题排查:
通过定位排查,发现里面有个缺陷,就是在重叠框和目标框过小的时候,容易导致出现出问题
NMS计算是IOU,就是计算重叠面积,占据两个框总面积减去重叠框的比例
如果其中一个面积比较大,一个面积比较小,这个时候哪怕完全重叠,他们的IOU的NMS也比较低,通过阈值过滤会失败,导致出现两个重叠的方框。
比如:我设置的阈值是0.4
有两个方框A和B
方框A的面积是1000,而B的面积是10,他们完全重叠,但是计算出来的NMS会很低。
10/(1000+10 -10) = 0.01 ,这个时候会算作两个方框,那怎么处理了。
解决方案
我添加一个阈值my_iou_threshold,就是IOU和自身面积的比值,如果超于0.5或者0.8 这个看项目设置,那么也进行合并,修改代码如下:
static void nms_sorted_bboxes(const std::vector<ObjectDef>& faceObjectDefs, std::vector<int>& picked,
float nms_threshold=0.4, float my_iou_threshold=0.5) {
picked.clear();
const int n = faceObjectDefs.size();
std::vector<float> areas(n);
for (int i = 0; i < n; i++) {
areas[i] = faceObjectDefs[i].bbox.rect.area();
}
for (int i = 0; i < n; i++) {
const ObjectDef& a = faceObjectDefs[i];
int keep = 1;
for (int j = 0; j < (int)picked.size(); j++) {
const ObjectDef& b = faceObjectDefs[picked[j]];
// intersection over union
float inter_area = intersection_area(a, b);
float union_area = areas[i] + areas[picked[j]] - inter_area;
if ((inter_area / areas[i] > my_iou_threshold) || (inter_area / areas[picked[j]] > my_iou_threshold)
|| (inter_area / union_area > nms_threshold))
keep = 0;
float IoU = inter_area / union_area
//if (inter_area / union_area > nms_threshold)
// keep = 0;
}
if (keep)
picked.push_back(i);
}
}