深度学习(目标检测)---非极大值抑制(nonMaximumSuppression)

更新时间:2023-06-24 11:36:17 阅读: 评论:0

深度学习(⽬标检测)---⾮极⼤值抑制
(nonMaximumSuppression)
理论基础
说实话,讲理论基础实在不是我的强项,但是还是得硬着头⽪来讲,希望我的讲解不⾄于晦涩难懂。
⾮极⼤值抑制,简称为NMS算法。是⼀种获取局部最⼤值的有效⽅法。在3领域中,假设⼀个⾏向量的长度为w,从左向右,由第⼀个到第w个和其3领域中的数值进⾏⽐对。
如果某个i⼤于i+1并且⼩于i-1,则其为⼀个绝不最⼤值,同时也就意味着i+1不是⼀个局部最⼤值,所以将i移动2个步长,从i+2开始继续向后进⾏⽐较判断。如果某个i不满⾜上述条件,则将i+1,继续对i+1进⾏⽐对。当⽐对到最后⼀个w时,直接将w设置为局部最⼤值。算法流程如下图所⽰。
名字设计
应⽤范围
猫咪壁纸
⾮极⼤值抑制NMS在⽬标检测,定位等领域是⼀种被⼴泛使⽤的⽅法。对于⽬标具体位置定位过程,不管是使⽤sw(sliding Window)还是ss(lective ar ch)⽅法,都会产⽣好多的候选区域。实际看到的情形就是好多区域的交叉重叠,难以满⾜实际的应⽤。如下图所⽰。
针对该问题有3种传统的解决思路。
第⼀种,选取好多矩形框的交集,即公共区域作为最后的⽬标区域。
第⼆种,选取好多矩形框的并集,即所有矩形框的最⼩外截矩作为⽬标区域。当然这⾥也不是只要相交就直接取并集,需要相交的框满⾜交集占最⼩框的⾯积达到⼀定⽐例(也就是阈值)才合并。
第三种,也就是本⽂的NMS,简单的说,对于有相交的就选取其中置信度最⾼的⼀个作为最后结果,对于没相交的就直接保留下来,作为最后结果。
总体来说,3种处理思路都各有千秋,不能⼀概评论哪种好坏。各种顶会论⽂也会选择不同的处理⽅法。
程序实现
三叔是谁本⽂提供了nonMaximumSuppression的c语⾔,c++,M语⾔,三个版本。
其中,c语⾔版本为opencv的源码这⾥摘出并进⾏相关的注释。sort为排序函数,这⾥是最基本的选择排序算法的实现。nonMaximum Suppression为具体⾮极⼤值抑制的实现。
[cpp]
1. static void sort(int n, const float* x, int* indices)
2. {
3. // 排序函数,排序后进⾏交换的是indices中的数据
4. // n:排序总数// x:带排序数// indices:初始为0~n-1数⽬
5.
6. int i, j;
7. for (i = 0; i < n; i++)开学第一天作文
8. for (j = i + 1; j < n; j++)
9.        {
10. if (x[indices[j]] > x[indices[i]])
11.            {
12. //float x_tmp = x[i];
13. int index_tmp = indices[i];
14. //x[i] = x[j];
15.                indices[i] = indices[j];
16. //x[j] = x_tmp;
17.                indices[j] = index_tmp;
18.            }
19.        }
20. }
[cpp]
1. int nonMaximumSuppression(int numBoxes, const CvPoint *points,
2. const CvPoint *oppositePoints, const float *score,
3. float overlapThreshold,
4. int *numBoxesOut, CvPoint **pointsOut,
5.                          CvPoint **oppositePointsOut, float **scoreOut)
6. {
7.
8. // numBoxes:窗⼝数⽬// points:窗⼝左上⾓坐标点// oppositePoints:窗⼝右下⾓坐标点
9. // score:窗⼝得分// overlapThreshold:重叠阈值控制// numBoxesOut:输出窗⼝数⽬
10. // pointsOut:输出窗⼝左上⾓坐标点// oppositePoints:输出窗⼝右下⾓坐标点
11. // scoreOut:输出窗⼝得分
12. int i, j, index;
13. float* box_area = (float*)malloc(numBoxes * sizeof(float));    // 定义窗⼝⾯积变量并分配空间
14. int* indices = (int*)malloc(numBoxes * sizeof(int));          // 定义窗⼝索引并分配空间
15. int* is_suppresd = (int*)malloc(numBoxes * sizeof(int));    // 定义是否抑制表标志并分配空间
16. // 初始化indices、is_suppersd、box_area信息
17. for (i = 0; i < numBoxes; i++)
18.    {
19.        indices[i] = i;
20.        is_suppresd[i] = 0;
21.        box_area[i] = (float)( (oppositePoints[i].x - points[i].x + 1) *
孩子高烧22.                                (oppositePoints[i].y - points[i].y + 1));
23.    }
24. // 对输⼊窗⼝按照分数⽐值进⾏排序,排序后的编号放在indices中
25.    sort(numBoxes, score, indices);
26. for (i = 0; i < numBoxes; i++)                // 循环所有窗⼝
27.    {
28. if (!is_suppresd[indices[i]])          // 判断窗⼝是否被抑制
29.        {
30. for (j = i + 1; j < numBoxes; j++)    // 循环当前窗⼝之后的窗⼝
31.            {
32. if (!is_suppresd[indices[j]])  // 判断窗⼝是否被抑制
33.                {
34. int x1max = max(points[indices[i]].x, points[indices[j]].x);                    // 求两个窗⼝左上⾓x坐标最⼤值
35. int x2min = min(oppositePoints[indices[i]].x, oppositePoints[indices[j]].x);    // 求两个窗⼝右下⾓x坐
标最⼩值
36. int y1max = max(points[indices[i]].y, points[indices[j]].y);                    // 求两个窗⼝左上⾓y坐标最⼤值
37. int y2min = min(oppositePoints[indices[i]].y, oppositePoints[indices[j]].y);    // 求两个窗⼝右下⾓y坐
标最⼩值
38. int overlapWidth = x2min - x1max + 1;            // 计算两矩形重叠的宽度
39. int overlapHeight = y2min - y1max + 1;          // 计算两矩形重叠的⾼度
40. if (overlapWidth > 0 && overlapHeight > 0)
41.                    {
42. float overlapPart = (overlapWidth * overlapHeight) / box_area[indices[j]];    // 计算重叠的⽐率
43. if (overlapPart > overlapThreshold)          // 判断重叠⽐率是否超过重叠阈值
44.                        {
45.                            is_suppresd[indices[j]] = 1;          // 将窗⼝j标记为抑制
46.                        }
47.                    }
48.                }
49.            }
50.        }
51.    }
52.
53.    *numBoxesOut = 0;    // 初始化输出窗⼝数⽬0
54. for (i = 0; i < numBoxes; i++)
55.    {
56. if (!is_suppresd[i]) (*numBoxesOut)++;    // 统计输出窗⼝数⽬
57.    }
钟的简笔画58.
59.    *pointsOut = (CvPoint *)malloc((*numBoxesOut) * sizeof(CvPoint));          // 分配输出窗⼝左上⾓坐标空间
60.    *oppositePointsOut = (CvPoint *)malloc((*numBoxesOut) * sizeof(CvPoint));  // 分配输出窗⼝右下⾓坐标空间
61.    *scoreOut = (float *)malloc((*numBoxesOut) * sizeof(float));                // 分配输出窗⼝得分空间
62.    index = 0;
63. for (i = 0; i < numBoxes; i++)                  // 遍历所有输⼊窗⼝
64.    {
65. if (!is_suppresd[indices[i]])            // 将未发⽣抑制的窗⼝信息保存到输出信息中
66.        {
67.            (*pointsOut)[index].x = points[indices[i]].x;
68.            (*pointsOut)[index].y = points[indices[i]].y;
69.            (*oppositePointsOut)[index].x = oppositePoints[indices[i]].x;
70.            (*oppositePointsOut)[index].y = oppositePoints[indices[i]].y;
71.            (*scoreOut)[index] = score[indices[i]];
72.            index++;
73.        }新古典经济学
74.
74.
75.    }
76.
77.    free(indices);          // 释放indices空间
78.    free(box_area);        // 释放box_area空间
79.    free(is_suppresd);    // 释放is_suppresd空间
80.
81. return LATENT_SVM_OK;
82. }
c++版本程序如下所⽰,根据opencv源码改编,vs2010实测运⾏完美。由于c和c++版本基本⼀个思路,因此将这两个的思路⼀起讲解。
整体程序分为两部分,sort函数主要实现候选框的置信度从⾼到低的排序,是基于基本的选择排序实现。nonMaximumSuppression主要实现⾮极⼤值抑制算法。算法思路为,先根据候选框的points 和oppositePoints 求出每个候选框的⾯积box_area,并将标签is_suppres d全部置为0。通过⼀个⼆重for循环将所有的候选框进⾏⽐对,这⾥的循环是从置信度最⾼的窗⼝进⾏⽐对,每层外循环中置信度最⾼的保留,其余的只要⼤于规定阈值overlapThreshold就舍弃,不⼤于阈值的保留下来。最终输出NMS处理后的结果。
[cpp]
1. static void sort(int n, const vector<float> x, vector<int> indices)
2. {
3. // 排序函数,排序后进⾏交换的是indices中的数据
4. // n:排序总数// x:带排序数// indices:初始为0~n-1数⽬
5.
6. int i, j;
7. for (i = 0; i < n; i++)
8. for (j = i + 1; j < n; j++)
9.        {
10. if (x[indices[j]] > x[indices[i]])
11.            {
12. //float x_tmp = x[i];
13. int index_tmp = indices[i];
14. //x[i] = x[j];
15.                indices[i] = indices[j];
16. //x[j] = x_tmp;觳觫怎么读
17.                indices[j] = index_tmp;
18.            }
19.        }
20. }
[cpp]
1. int nonMaximumSuppression(int numBoxes, const vector<CvPoint> points,const vector<CvPoint> oppositeP
oints,
2. const vector<float> score,    float overlapThreshold,int& numBoxesOut, vector<CvPoint>& pointsOut,
3.    vector<CvPoint>& oppositePointsOut, vector<float> scoreOut)
4. {
5. // 实现检测出的矩形窗⼝的⾮极⼤值抑制nms
6. // numBoxes:窗⼝数⽬// points:窗⼝左上⾓坐标点// oppositePoints:窗⼝右下⾓坐标点// score:窗⼝得分
7. // overlapThreshold:重叠阈值控制// numBoxesOut:输出窗⼝数⽬// pointsOut:输出窗⼝左上⾓坐标点
8. // oppositePoints:输出窗⼝右下⾓坐标点// scoreOut:输出窗⼝得分
8. // oppositePoints:输出窗⼝右下⾓坐标点// scoreOut:输出窗⼝得分
9. int i, j, index;
10.    vector<float> box_area(numBoxes);            // 定义窗⼝⾯积变量并分配空间
11.    vector<int> indices(numBoxes);                    // 定义窗⼝索引并分配空间
12.    vector<int> is_suppresd(numBoxes);          // 定义是否抑制表标志并分配空间
13. // 初始化indices、is_suppersd、box_area信息
14. for (i = 0; i < numBoxes; i++)
15.    {
16.        indices[i] = i;
17.        is_suppresd[i] = 0;
18.        box_area[i] = (float)( (oppositePoints[i].x - points[i].x + 1) *(oppositePoints[i].y - points[i].y + 1));
19.    }
20. // 对输⼊窗⼝按照分数⽐值进⾏排序,排序后的编号放在indices中
21.    sort(numBoxes, score, indices);
22. for (i = 0; i < numBoxes; i++)                // 循环所有窗⼝
23.    {
24. if (!is_suppresd[indices[i]])          // 判断窗⼝是否被抑制
25.        {
26. for (j = i + 1; j < numBoxes; j++)    // 循环当前窗⼝之后的窗⼝
27.            {
28. if (!is_suppresd[indices[j]])  // 判断窗⼝是否被抑制
29.                {
30. int x1max = max(points[indices[i]].x, points[indices[j]].x);                    // 求两个窗⼝左上⾓x坐标最⼤值
31. int x2min = min(oppositePoints[indices[i]].x, oppositePoints[indices[j]].x);    // 求两个窗⼝右下⾓x坐
标最⼩值
32. int y1max = max(points[indices[i]].y, points[indices[j]].y);                    // 求两个窗⼝左上⾓y坐标最⼤值
33. int y2min = min(oppositePoints[indices[i]].y, oppositePoints[indices[j]].y);    // 求两个窗⼝右下⾓y坐
标最⼩值
34. int overlapWidth = x2min - x1max + 1;    // 计算两矩形重叠的宽度
35. int overlapHeight = y2min - y1max + 1;    // 计算两矩形重叠的⾼度
36. if (overlapWidth > 0 && overlapHeight > 0)
37.                    {
38. float overlapPart = (overlapWidth * overlapHeight) / box_area[indices[j]];    // 计算重叠的⽐率
39. if (overlapPart > overlapThreshold)  // 判断重叠⽐率是否超过重叠阈值
40.                        {
41.                            is_suppresd[indices[j]] = 1;    // 将窗⼝j标记为抑制
42.                        }
43.                    }
44.                }
45.            }
46.        }
47.    }
48.
49.    numBoxesOut = 0;    // 初始化输出窗⼝数⽬0
50. for (i = 0; i < numBoxes; i++)
51.    {
52. if (!is_suppresd[i]) numBoxesOut++;    // 统计输出窗⼝数⽬
53.    }
54.    index = 0;
55. for (i = 0; i < numBoxes; i++)            // 遍历所有输⼊窗⼝
56.    {

本文发布于:2023-06-24 11:36:17,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1052701.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:排序   重叠   是否   抑制   空间   思路
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图