NMS(非极大值抑制) C++/C#/Python 代码实现

NMS

python

import numpy as np

def iou(A, B):
    # 左上右下坐标(x1,y1,x2,y2)
    w = max(0, min(A[2], B[2]) - max(A[0], B[0]) + 1)
    h = max(0, min(A[3], B[3]) - max(A[1], B[1]) + 1)
    area1 = (A[2] - A[0] + 1) * (A[3] - A[1] + 1)
    area2 = (B[2] - B[0] + 1) * (B[3] - B[1] + 1)
    inter = w * h
    union = area1 + area2 - inter
    return inter / union


def nms(dets, thresh):
    """Pure Python NMS baseline."""
    # x1、y1、x2、y2、以及score赋值
    x1 = dets[:, 0]  # xmin
    y1 = dets[:, 1]  # ymin
    x2 = dets[:, 2]  # xmax
    y2 = dets[:, 3]  # ymax
    scores = dets[:, 4]
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    # argsort()返回数组值从小到大的索引值
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:  # 还有数据
        i = order[0]
        keep.append(i)
        # 计算当前概率最大矩形框与其他矩形框的相交框的坐标
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])

        # 计算相交框的面积
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        # 计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)
        IOU = inter / (areas[i] + areas[order[1:]] - inter)
        # 找到重叠度不高于阈值的矩形框索引
        left_index = np.where(IOU <= thresh)[0]
        # 将order序列更新,由于前面得到的矩形框索引要比矩形框在原order序列中的索引小1,所以要把这个1加回来
        order = order[left_index + 1]
    return keep


if __name__ == '__main__':
    dets = [[0, 0, 100, 101, 0.9], [5, 6, 90, 110, 0.7], [17, 19, 80, 120, 0.8], [10, 8, 115, 105, 0.5]]
    dets = np.array(dets)
    keep = nms(dets, 0.5)
    print(keep)
    print("%.4f" % iou(dets[0], dets[2]))

c++

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

float IOU(vector<float> &A, vector<float> &B){
	// 左上右下坐标(x1,y1,x2,y2)
	float w = max(0.0f, min(A[2], B[2]) - max(A[0], B[0]) + 1);
	float h = max(0.0f, min(A[3], B[3]) - max(A[1], B[1]) + 1);
	float area1 = (A[2] - A[0] + 1) * (A[3] - A[1] + 1);
	float area2 = (B[2] - B[0] + 1) * (B[3] - B[1] + 1);
	float inter = w * h;
	float iou = inter / (area1 + area2 - inter);
	return iou;
}

bool sort_score(vector<float> &box1, vector<float> &box2){
	return (box1[4] > box2[4]);
}

void NMS(vector<vector<float> > &vec_boxs, float thresh) {
	// box[0:4]: x1, x2, y1, y2; box[4]: score
	// 按分值从大到小排序
	std::sort(vec_boxs.begin(), vec_boxs.end(), sort_score);
	//标志,false代表留下,true代表扔掉
	vector<bool> del(vec_boxs.size(), false);
	for (size_t i = 0; i < vec_boxs.size()-1; i++){
		if (!del[i]){
			for (size_t j = i + 1; j < vec_boxs.size(); j++){
				if (!del[j] && IOU(vec_boxs[i], vec_boxs[j]) >= thresh){
						del[j] = true; //IOU大于阈值扔掉
				}
			}
		}
	}
	vector<vector<float>> result;
	for (size_t i = 0; i < vec_boxs.size(); i++){
		if (!del[i]) {
			result.push_back(vec_boxs[i]);
		}
	}
	vec_boxs.clear();
	vector<vector<float> >().swap(vec_boxs);
	vec_boxs = result;
}

int main(){
	vector<vector<float> > vec_boxs = { { 0, 0, 100, 101, 0.9f }, { 5, 6, 90, 110, 0.7f }, 
										{ 17, 19, 80, 120, 0.8f }, { 10, 8, 115, 105, 0.5f }};
	NMS(vec_boxs, 0.5f);
	for (size_t i = 0; i < vec_boxs.size(); i++){
		cout << vec_boxs[i][0] << " " << vec_boxs[i][1] << " " << vec_boxs[i][2] 
			 << " " << vec_boxs[i][3] << " " << vec_boxs[i][4] << endl;
	}
	system("pause");
	return 0;
}

C#

        static int SortItem(List<float> item1, List<float> item2)
        {
            //传入的对象为列表中的对象
            //进行两两比较,用左边的和右边的 按条件 比较
            //返回值规则与接口方法相同
            if (item1[4] > item2[4]) return -1;  //降序
            else return 1; //升序
        }

        /* 计算iou值 */
        static float IOU(List<float> A, List<float> B)
        {
            // 左上右下坐标(x1,y1,x2,y2)
            float w = Math.Max(0.0f, Math.Min(A[2], B[2]) - Math.Max(A[0], B[0]) + 1);
            float h = Math.Max(0.0f, Math.Min(A[3], B[3]) - Math.Max(A[1], B[1]) + 1);
            float area1 = (A[2] - A[0] + 1) * (A[3] - A[1] + 1);
            float area2 = (B[2] - B[0] + 1) * (B[3] - B[1] + 1);
            float inter = w * h;
            float iou = inter / (area1 + area2 - inter);
            return iou;
        }
        public static void NMS(ref List<List<float>> vec_boxs, float thresh)
        {

            // box[0:4]: x1, x2, y1, y2; box[4]: score
            // 按分值从大到小排序
            vec_boxs.Sort(SortItem);
            
            //标志,false代表留下,true代表扔掉
            List<bool> del = new List<bool>(vec_boxs.Count());
            for(int i = 0;i < vec_boxs.Count;i++)
                del.Add(false);

            for(int i = 0; i < vec_boxs.Count-1; i++)
            {
                if(!del[i])
                {
                    for(int j = i + 1; j < vec_boxs.Count; j++)
                    {
                        if(!del[j] && IOU(vec_boxs[i], vec_boxs[j]) >= thresh)
                        {
                            del[j] = true;  //IOU大于阈值扔掉
                        }
                    }
                }
            }

            List<List<float>> result = new List<List<float>>();
            for(int i = 0; i < vec_boxs.Count(); i++)
            {
                if(!del[i])
                {
                    result.Add(vec_boxs[i]);    
                }
            }
            vec_boxs.Clear();

            vec_boxs = result;

        }
        static void test036()
        {
            List<List<float>> vec_boxs = new List<List<float>>();
            
            float[] numstr1 = new float[] { 100.2f, 100.0f, 210.0f, 210.0f, 0.72f, 1.0f };
            List<float> aa1 = new List<float>(numstr1);
            float[] numstr2 = new float[] { 250.0f, 250.0f, 420.3f, 420.0f, 0.8f, 2.0f };
            List<float> aa2 = new List<float>(numstr2);
            float[] numstr3 = new float[] { 220.0f, 220.0f, 320.4f, 330.0f, 0.92f, 1.0f };
            List<float> aa3 = new List<float>(numstr3);
            float[] numstr4 = new float[] { 230.0f, 240.6f, 325.0f, 330.0f, 0.81f, 2.0f };
            List<float> aa4 = new List<float>(numstr4);
            float[] numstr5 = new float[] { 220.0f, 230.0f, 315.0f, 340.9f, 0.9f, 1.0f };
            List<float> aa5 = new List<float>(numstr5);

            vec_boxs.Add(aa1);
            vec_boxs.Add(aa2);
            vec_boxs.Add(aa3);
            vec_boxs.Add(aa4);
            vec_boxs.Add(aa5);

            NMS(ref vec_boxs, 0.1f);

            for(int i = 0; i < vec_boxs.Count; i++)
            {
                
                Console.Write(vec_boxs[i][0] + " ");
                Console.Write(vec_boxs[i][1] + " ");
                Console.Write(vec_boxs[i][2] + " ");
                Console.Write(vec_boxs[i][3] + " ");
                Console.Write(vec_boxs[i][4] + " ");
                Console.WriteLine(vec_boxs[i][5]);
            }



        }

Soft-NMS

Python

import numpy as np

def soft_nms(dets, sigma=0.5, Nt=0.5, method=2, threshold=0.1):
    box_len = len(dets)   # box的个数
    for i in range(box_len):
        tmpx1, tmpy1, tmpx2, tmpy2, ts = dets[i, 0], dets[i, 1], dets[i, 2], dets[i, 3], dets[i, 4]
        max_pos = i
        max_scores = ts

        # get max box
        pos = i+1
        while pos < box_len:
            if max_scores < dets[pos, 4]:
                max_scores = dets[pos, 4]
                max_pos = pos
            pos += 1

        # add max box as a detection
        dets[i, :] = dets[max_pos, :]

        # swap ith box with position of max box
        dets[max_pos, 0] = tmpx1
        dets[max_pos, 1] = tmpy1
        dets[max_pos, 2] = tmpx2
        dets[max_pos, 3] = tmpy2
        dets[max_pos, 4] = ts

        # 将置信度最高的 box 赋给临时变量
        tmpx1, tmpy1, tmpx2, tmpy2, ts = dets[i, 0], dets[i, 1], dets[i, 2], dets[i, 3], dets[i, 4]

        pos = i+1
        # NMS iterations, note that box_len changes if detection boxes fall below threshold
        while pos < box_len:
            x1, y1, x2, y2 = dets[pos, 0], dets[pos, 1], dets[pos, 2], dets[pos, 3]

            area = (x2 - x1 + 1)*(y2 - y1 + 1)

            iw = (min(tmpx2, x2) - max(tmpx1, x1) + 1)
            ih = (min(tmpy2, y2) - max(tmpy1, y1) + 1)
            if iw > 0 and ih > 0:
                overlaps = iw * ih
                ious = overlaps / ((tmpx2 - tmpx1 + 1) * (tmpy2 - tmpy1 + 1) + area - overlaps)

                if method == 1:    # 线性
                    if ious > Nt:
                        weight = 1 - ious
                    else:
                        weight = 1
                elif method == 2:  # gaussian
                    weight = np.exp(-(ious**2) / sigma)
                else:              # original NMS
                    if ious > Nt:
                        weight = 0
                    else:
                        weight = 1

                # 赋予该box新的置信度
                dets[pos, 4] = weight * dets[pos, 4]

                # 如果box得分低于阈值thresh,则通过与最后一个框交换来丢弃该框
                if dets[pos, 4] < threshold:
                    dets[pos, 0] = dets[box_len-1, 0]
                    dets[pos, 1] = dets[box_len-1, 1]
                    dets[pos, 2] = dets[box_len-1, 2]
                    dets[pos, 3] = dets[box_len-1, 3]
                    dets[pos, 4] = dets[box_len-1, 4]

                    box_len = box_len-1
                    pos = pos-1
            pos += 1

    keep = [i for i in range(box_len)]
    return keep


if __name__ == '__main__':
    dets = [[0, 0, 100, 101, 0.9], [5, 6, 90, 110, 0.7], [17, 19, 80, 120, 0.8], [10, 8, 115, 105, 0.5]]
    dets = np.array(dets)
    result = soft_nms(dets, 0.5)
    print(result)

C++

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

vector<vector<float> > Soft_NMS(vector<vector<float> > vec_boxs, float sigma = 0.5, float Nt = 0.5, float threshold = 0.1, unsigned int method = 0){
	int box_len = vec_boxs.size();
	for (int i = 0; i < box_len; i++){
		float tmp_x1 = vec_boxs[i][0];
		float tmp_y1 = vec_boxs[i][1];
		float tmp_x2 = vec_boxs[i][2];
		float tmp_y2 = vec_boxs[i][3];
		float tmp_score = vec_boxs[i][4];
		int max_pos = i;
		float max_scores = tmp_score;

		// get max box
		int pos = i + 1;
		while (pos < box_len){
			if (max_scores < vec_boxs[pos][4]){
				max_scores = vec_boxs[pos][4];
				max_pos = pos;
			}
			pos++;
		}

		//add max box as a detection
		vec_boxs[i][0] = vec_boxs[max_pos][0];
		vec_boxs[i][1] = vec_boxs[max_pos][1];
		vec_boxs[i][2] = vec_boxs[max_pos][2];
		vec_boxs[i][3] = vec_boxs[max_pos][3];
		vec_boxs[i][4] = vec_boxs[max_pos][4];

		// swap ith box with position of max box
		vec_boxs[max_pos][0] = tmp_x1;
		vec_boxs[max_pos][1] = tmp_y1;
		vec_boxs[max_pos][2] = tmp_x2;
		vec_boxs[max_pos][3] = tmp_y2;
		vec_boxs[max_pos][4] = tmp_score;

		// 将置信度最高的 box 赋给临时变量
		tmp_x1 = vec_boxs[i][0];
		tmp_y1 = vec_boxs[i][1];
		tmp_x2 = vec_boxs[i][2];
		tmp_y2 = vec_boxs[i][3];
		tmp_score = vec_boxs[i][4];

		pos = i + 1;
		while (pos < box_len){
			float x1 = vec_boxs[pos][0];
			float y1 = vec_boxs[pos][1];
			float x2 = vec_boxs[pos][2];
			float y2 = vec_boxs[pos][3];
			float area = (x2 - x1 + 1) * (y2 - y1 + 1);

			float iw = (min(tmp_x2, x2) - max(tmp_x1, x1) + 1);
			float ih = (min(tmp_y2, y2) - max(tmp_y1, y1) + 1);
			if (iw > 0 && ih> 0){
				float overlaps = iw * ih;
				float iou = overlaps / ((tmp_x2 - tmp_x1 + 1) * (tmp_y2 - tmp_y1 + 1) + area - overlaps);

				float weight = 0;
				if (method == 1){ //线性
					if (iou > Nt){
						weight = 1 - iou;
					}
					else{
						weight = 1;
					}
				}
				else if (method == 2){ // gaussian
					weight = exp(-(iou*iou) / sigma);
				}
				else{ // original NMS
					if (iou > Nt){
						weight = 0;
					}
					else{
						weight = 1;
					}
				}
				// 赋予该box新的置信度
				vec_boxs[pos][4] = weight * vec_boxs[pos][4];
				// 如果box得分低于阈值thresh,则通过与最后一个框交换来丢弃该框
				if (vec_boxs[pos][4] < threshold){
					vec_boxs[pos][0] = vec_boxs[box_len - 1][0];
					vec_boxs[pos][1] = vec_boxs[box_len - 1][1];
					vec_boxs[pos][2] = vec_boxs[box_len - 1][2];
					vec_boxs[pos][3] = vec_boxs[box_len - 1][3];
					vec_boxs[pos][4] = vec_boxs[box_len - 1][4];
					box_len--;
					pos--;
				}
			}
			pos++;
		}
	}
	vector<vector<float> > result(box_len);
	for (int i = 0; i < box_len; i++){
		result[i].resize(5);
		result[i][0] = vec_boxs[i][0];
		result[i][1] = vec_boxs[i][1];
		result[i][2] = vec_boxs[i][2];
		result[i][3] = vec_boxs[i][3];
		result[i][4] = vec_boxs[i][4];
	}
	return result;
}

int main(){
	vector<vector<float> > vec_boxs = { { 0, 0, 100, 101, 0.9f }, { 5, 6, 90, 110, 0.7f }, 
										{ 17, 19, 80, 120, 0.8f }, { 10, 8, 115, 105, 0.5f }};
	vector<vector<float> > result = Soft_NMS(vec_boxs, 0.5, 0.5, 0.1, 2);
	for (size_t i = 0; i < result.size(); i++){
		cout << result[i][0] << " " << result[i][1] << " " << result[i][2]
			<< " " << result[i][3] << " " << result[i][4] << endl;
	}
	system("pause");
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NMS(Non-Maximum Suppression)非极大值抑制是目标检测中常用的一种算法,用于消除重叠的边界框,并筛选出最优的边界框。下面是Java实现NMS的完整源码。 ```java import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * NMS(Non-Maximum Suppression)非极大值抑制算法的Java实现 */ public class NMS { /** * 定义一个边界框类,用于存储边界框的坐标和置信度 */ private static class BoundingBox { float x1, y1, x2, y2; // 左上角和右下角的坐标 float confidence; // 置信度 BoundingBox(float x1, float y1, float x2, float y2, float confidence) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.confidence = confidence; } float getArea() { return (x2 - x1 + 1) * (y2 - y1 + 1); } } /** * 定义一个比较器类,用于按照置信度降序排序 */ private static class ConfidenceComparator implements Comparator<BoundingBox> { @Override public int compare(BoundingBox o1, BoundingBox o2) { if (o1.confidence > o2.confidence) { return -1; } else if (o1.confidence < o2.confidence) { return 1; } return 0; } } /** * NMS算法的主要实现 * @param boxes 边界框列表 * @param overlapThreshold IOU阈值 * @return 非极大值抑制后的边界框列表 */ public static List<BoundingBox> nms(List<BoundingBox> boxes, float overlapThreshold) { // 按照置信度降序排序 Collections.sort(boxes, new ConfidenceComparator()); List<BoundingBox> result = new ArrayList<>(); while (!boxes.isEmpty()) { BoundingBox box = boxes.remove(0); result.add(box); List<BoundingBox> toRemove = new ArrayList<>(); for (BoundingBox b : boxes) { float iou = getIOU(box, b); if (iou > overlapThreshold) { toRemove.add(b); } } boxes.removeAll(toRemove); } return result; } /** * 计算两个边界框的IOU(Intersection over Union) * @param box1 边界框1 * @param box2 边界框2 * @return IOU值 */ private static float getIOU(BoundingBox box1, BoundingBox box2) { float area1 = box1.getArea(); float area2 = box2.getArea(); float x1 = Math.max(box1.x1, box2.x1); float y1 = Math.max(box1.y1, box2.y1); float x2 = Math.min(box1.x2, box2.x2); float y2 = Math.min(box1.y2, box2.y2); float w = Math.max(0, x2 - x1 + 1); float h = Math.max(0, y2 - y1 + 1); float inter = w * h; return inter / (area1 + area2 - inter); } } ``` 使用示例: ```java public class NMSDemo { public static void main(String[] args) { List<NMS.BoundingBox> boxes = new ArrayList<>(); boxes.add(new NMS.BoundingBox(10, 10, 20, 20, 0.9f)); boxes.add(new NMS.BoundingBox(15, 15, 25, 25, 0.8f)); boxes.add(new NMS.BoundingBox(30, 30, 40, 40, 0.7f)); List<NMS.BoundingBox> result = NMS.nms(boxes, 0.5f); for (NMS.BoundingBox box : result) { System.out.println(box.x1 + "," + box.y1 + "," + box.x2 + "," + box.y2 + "," + box.confidence); } } } ``` 输出结果: ``` 10.0,10.0,20.0,20.0,0.9 30.0,30.0,40.0,40.0,0.7 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值