c++|NMS 原理和c++实现,已测试通过

NMS(非极大抑制)是深度学习目标检测中常用的小算法,用来过滤掉同一个物体上的那些置信度较低的bbboxes,最后只剩下该目标检测框集中最大置信度的那个。
算法原理 【c++|NMS 原理和c++实现,已测试通过】说它是小算法的原因是其原理很简单。
1)先对输入检测框按置信度由高到低排序
2)挑选第一个检测框(即最高置信度,记为A)和其它检测框(记为B)进行iou计算
3)如果iou大于nmsThreshold, 那就将B清除掉
4)跳转到2)从剩余得框集里面找置信度最大得框和其它框分别计算iou
5)直到所有框都过滤完。
代码实现
box的数据结构

struct Box{ float left, top, right, bottom, confidence; float landmark[10]; cv::Rect cvbox() const{return cv::Rect(left, top, right-left, bottom-top); } float width()const{return std::max(0.0f, right-left); } float height()const{return std::max(0.0f, bottom-top); } float area()const{return width() * height(); } float get_left(){return left; } void set_left(float value){left = value; } float get_top(){return top; } void set_top(float value){top = value; } float get_right(){return right; } void set_right(float value){right = value; } float get_bottom(){return bottom; } void set_bottom(float value){bottom = value; } float get_confidence(){return confidence; } void set_confidence(float value){confidence = value; } };

NMS算法
static void cpu_nms(std::vector& boxes, std::vector& output, float threshold){// 先把boxes的按照置信度从大到小排序 std::sort(boxes.begin(), boxes.end(), [](std::vector::const_reference a, std::vector::const_reference b){ return a.confidence > b.confidence; }); // 清理输出的缓存 output.clear(); // 创建和boxes等量的bool向量,用来标记过滤,默认全为false std::vector remove_flags(boxes.size()); // 开始遍历 for(int i = 0; i < boxes.size(); ++i){ // 刚开始remove_flags均为false, if(remove_flags[i]) continue; // 经过上面的排序可以知道,第0个位置一定是置信度最大的那个,是我们的候选项,因此需要删除其他的候选框 auto& a = boxes[i]; // 把最大的先放到输出的向量里 output.push_back(a); // 继续遍历0后面的元素,所以j=i+1 for(int j = i + 1; j < boxes.size(); ++j){ // 第1个位置也为false if(remove_flags[j]) continue; // 此时拿到第一个位置的数据 auto& b = boxes[j]; // 和第一个进行计算iou,如果iou阈值重合大于愈合iz,直接删除第1个位置的框,此时说明该框已经废弃,因此flag设置为true即可 if(iou(a, b) >= threshold) remove_flags[j] = true; } } //综上,可以发现已经被废弃的box不会参与后面是循环,这样可以高性能实现nms }

iou算法
static float iou(const Box& a, const Box& b){ float cleft= std::max(a.left, b.left); float ctop= std::max(a.top, b.top); float cright= std::min(a.right, b.right); float cbottom= std::min(a.bottom, b.bottom); float c_area = std::max(cright - cleft, 0.0f) * std::max(cbottom - ctop, 0.0f); if(c_area == 0.0f) return 0.0f; float a_area = std::max(0.0f, a.right - a.left) * std::max(0.0f, a.bottom - a.top); float b_area = std::max(0.0f, b.right - b.left) * std::max(0.0f, b.bottom - b.top); return c_area / (a_area + b_area - c_area); }


    推荐阅读