void Yolov5PostProcess::nms(vector<vector<float>>& boxes, vector<int>& idxes, float threshold) { map<int, int> idx_map; for (int i = 0; i < boxes.size() - 1; ++i) { if (idx_map.find(i) != idx_map.end()) { continue; } for (int j = i + 1; j < boxes.size(); ++j) { if (idx_map.find(j) != idx_map.end()) { continue; } vector<float> Bbox1, Bbox2; Bbox1.push_back(boxes[i][0]); Bbox1.push_back(boxes[i][1]); Bbox1.push_back(boxes[i][2]); Bbox1.push_back(boxes[i][3]); Bbox2.push_back(boxes[j][0]); Bbox2.push_back(boxes[j][1]); Bbox2.push_back(boxes[j][2]); Bbox2.push_back(boxes[j][3]); float iou = box_iou(Bbox1, Bbox2); if (iou >= threshold) { idx_map[j] = 1; } } } for (int i = 0; i < boxes.size(); ++i) { if (idx_map.find(i) == idx_map.end()) { idxes.push_back(i); } } }详细解读一下这段代码
时间: 2024-04-28 12:23:50 浏览: 20
这段代码实现的是非极大值抑制(Non-Maximum Suppression,NMS)的功能,用于在目标检测中去除重复的边界框。
具体来说,这段代码输入参数 `boxes` 是一个二维数组,每一行代表一个边界框,其中每行的四个元素分别是左上角 x 坐标、左上角 y 坐标、右下角 x 坐标和右下角 y 坐标。`threshold` 是一个阈值,用于控制重叠度的大小,当两个边界框的重叠度大于等于该阈值时,就认为它们是重复的边界框之一,需要将其中一个去掉。
该代码首先创建了一个 `idx_map` 的 `map` 对象,用于记录需要去掉的边界框的索引。然后使用两重循环遍历所有边界框,对于每对边界框,计算它们的重叠度(即交并比,通过 `box_iou` 函数实现),如果大于等于阈值 `threshold`,则将其中一个边界框的索引加入到 `idx_map` 中。最后遍历所有边界框的索引,将不在 `idx_map` 中的索引加入到输出参数 `idxes` 中,即完成了非极大值抑制的过程。
相关问题
在vs2015 c++ .h中加入这段代码会报重定义 namespace cv_dnn { namespace { template <typename T> static inline bool SortScorePairDescend(const std::pair<float, T>& pair1, const std::pair<float, T>& pair2) { return pair1.first > pair2.first; } } // namespace inline void GetMaxScoreIndex(const std::vector<float>& scores, const float threshold, const int top_k, std::vector<std::pair<float, int> >& score_index_vec) { for (size_t i = 0; i < scores.size(); ++i) { if (scores[i] > threshold) { score_index_vec.push_back(std::make_pair(scores[i], i)); } } std::stable_sort(score_index_vec.begin(), score_index_vec.end(), SortScorePairDescend<int>); if (top_k > 0 && top_k < (int)score_index_vec.size()) { score_index_vec.resize(top_k); } } template <typename BoxType> inline void NMSFast_(const std::vector<BoxType>& bboxes, const std::vector<float>& scores, const float score_threshold, const float nms_threshold, const float eta, const int top_k, std::vector<int>& indices, float(*computeOverlap)(const BoxType&, const BoxType&)) { CV_Assert(bboxes.size() == scores.size()); std::vector<std::pair<float, int> > score_index_vec; GetMaxScoreIndex(scores, score_threshold, top_k, score_index_vec); // Do nms. float adaptive_threshold = nms_threshold; indices.clear(); for (size_t i = 0; i < score_index_vec.size(); ++i) { const int idx = score_index_vec[i].second; bool keep = true; for (int k = 0; k < (int)indices.size() && keep; ++k) { const int kept_idx = indices[k]; float overlap = computeOverlap(bboxes[idx], bboxes[kept_idx]); keep = overlap <= adaptive_threshold; } if (keep) indices.push_back(idx); if (keep && eta < 1 && adaptive_threshold > 0.5) { adaptive_threshold *= eta; } } } // copied from opencv 3.4, not exist in 3.0 template<typename Tp> static inline double jaccardDistance_(const Rect_<Tp>& a, const Rect<_Tp>& b) { Tp Aa = a.area(); Tp Ab = b.area(); if ((Aa + Ab) <= std::numeric_limits<Tp>::epsilon()) { // jaccard_index = 1 -> distance = 0 return 0.0; } double Aab = (a & b).area(); // distance = 1 - jaccard_index return 1.0 - Aab / (Aa + Ab - Aab); } template <typename T> static inline float rectOverlap(const T& a, const T& b) { return 1.f - static_cast<float>(jaccardDistance(a, b)); } void NMSBoxes(const std::vector<Rect>& bboxes, const std::vector<float>& scores, const float score_threshold, const float nms_threshold, std::vector<int>& indices, const float eta = 1, const int top_k = 0) { NMSFast(bboxes, scores, score_threshold, nms_threshold, eta, top_k, indices, rectOverlap); } }
在加入这段代码时,如果在同一个命名空间内有相同的函数或变量,则会报重定义的错误。如果你确定已经检查过代码,在其他地方没有定义相同的函数或变量,可以尝试将代码放在一个新的命名空间中。例如:
```cpp
namespace my_cv_dnn {
// 这里放你的代码
}
```
然后在使用时使用新的命名空间即可。
yolov5 postprocess
YOLOv5的后处理主要包括以下几个步骤:
1. 对网络输出进行解码,得到预测框的中心坐标、宽高、置信度和类别概率。
2. 对预测框进行筛选,去除置信度较低的框。
3. 对剩余的框进行非极大值抑制(NMS)处理,去除重叠度较高的框。
4. 根据阈值筛选出最终的检测结果。
下面是一个简单的yolov5后处理的Python代码示例:
```python
import torch
from torchvision.ops import nms
def yolov5_postprocess(outputs, conf_thresh=0.5, iou_thresh=0.5):
# 解码网络输出
preds = []
for output in outputs:
grid_size = output.shape[2]
stride = 1 / grid_size
anchor_grid = torch.tensor([[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]])
num_anchors = anchor_grid.shape[0]
output = output.view(-1, num_anchors * (5 + 80), grid_size * grid_size).permute(0, 2, 1)
xy_offset = torch.sigmoid(output[..., :2])
wh_offset = torch.exp(output[..., 2:4])
obj_conf = torch.sigmoid(output[..., 4:5])
class_prob = torch.sigmoid(output[..., 5:])
grid_x = torch.arange(grid_size).repeat(grid_size, 1).view([1, 1, grid_size, grid_size]).float()
grid_y = torch.arange(grid_size).repeat(grid_size, 1).t().view([1, 1, grid_size, grid_size]).float()
anchor_w = anchor_grid[:, 0:1].view((1, num_anchors, 1, 1))
anchor_h = anchor_grid[:, 1:2].view((1, num_anchors, 1, 1))
pred_x = (xy_offset[..., 0:1] + grid_x) * stride
pred_y = (xy_offset[..., 1:2] + grid_y) * stride
pred_w = (wh_offset[..., 0:1] * anchor_w) * stride
pred_h = (wh_offset[..., 1:2] * anchor_h) * stride
pred_conf = obj_conf * class_prob.max(2, keepdim=True)[0]
preds.append(torch.cat([pred_x, pred_y, pred_w, pred_h, pred_conf], dim=-1))
# 筛选预测框
preds = torch.cat(preds, dim=1)
mask = preds[..., 4] > conf_thresh
preds = preds[mask]
# 非极大值抑制
keep = nms(preds[..., :4], preds[..., 4], iou_thresh)
preds = preds[keep]
# 返回最终结果
return preds.tolist()
```
相关推荐
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)