這里寫目錄標題
- 問題描述
- 原因分析與解決方法:
- 后續及思考
- 參考文檔
問題描述
目標檢測模型輸出的檢測框存在內嵌情況。
原因分析與解決方法:
根據經驗,第一感覺是后處理nms
部分出了問題。來看下對應的代碼:
static float CalcIou(const vector<float> &box1, const vector<float> &box2)
{float area1 = box1[6];float area2 = box2[6];float xx1 = max(box1[0], box2[0]);float yy1 = max(box1[1], box2[1]);float xx2 = min(box1[2], box2[2]);float yy2 = min(box1[3], box2[3]);float w = max(0.0f, xx2 - xx1 + 1);float h = max(0.0f, yy2 - yy1 + 1);float inter = w * h;float ovr = inter /(area1 + area2 - inter);return ovr;
}static void MulticlassNms(vector<vector<float>>& bboxes, const vector<vector<float>>& vaildBox, float nmsThr)
{for (auto &item : vaildBox) { /* score, xcenter, ycenter, w, h, classId */float boxXCenter = item[XCENTER_IDX];float boxYCenter = item[YCENTER_IDX];float boxWidth = item[W_IDX];float boxHeight = item[H_IDX];float x1 = (boxXCenter - boxWidth / 2);float y1 = (boxYCenter - boxHeight / 2);float x2 = (boxXCenter + boxWidth / 2);float y2 = (boxYCenter + boxHeight / 2);float area = (x2 - x1 + 1) * (y2 - y1 + 1);bool keep = true;/* lx, ly, rx, ry, score, class id, area */vector<float> bbox {x1, y1, x2, y2, item[SCORE_IDX], item[CLSAA_ID_IDX], area};for (size_t j = 0; j < bboxes.size(); j++) {if (CalcIou(bbox, bboxes[j]) > nmsThr) {keep = false;break;}}if (keep) {bboxes.push_back(bbox);}}
}
目前分析最可能的原因是nms
的nmsThr
設置過大,沒能濾除重疊檢測框,原來nmsThr
設置的為0.45
,現調整為0.1
。
檢測框內嵌情況基本消失:
后續及思考
先給個結論,綜合的看下各個Loss函數的不同點::
IOU_Loss:主要考慮檢測框和目標框重疊面積。
GIOU_Loss:在IOU的基礎上,解決邊界框不重合時的問題。
DIOU_Loss:在IOU和GIOU的基礎上,考慮邊界框中心點距離的信息。
CIOU_Loss:在DIOU的基礎上,考慮邊界框寬高比的尺度信息。
此項目中用的是基本的IOU
,在推理性能足夠的情況下,可以考慮使用DIOU
,下面也給出使用DIOU
的nms
代碼:
static float CalcDiou(const vector<float>& box1, const vector<float>& box2) {float x1 = min(box1[0], box2[0]);float y1 = min(box1[1], box2[1]);float x2 = max(box1[2], box2[2]);float y2 = max(box1[3], box2[3]);float c_x1 = (box1[0] + box1[2]) / 2.0;float c_y1 = (box1[1] + box1[3]) / 2.0;float c_x2 = (box2[0] + box2[2]) / 2.0;float c_y2 = (box2[1] + box2[3]) / 2.0;float dist_center = sqrt((c_x1 - c_x2) * (c_x1 - c_x2) + (c_y1 - c_y2) * (c_y1 - c_y2));float w = max(0.0f, x2 - x1);float h = max(0.0f, y2 - y1);float intersection = w * h;float area1 = (box1[2] - box1[0]) * (box1[3] - box1[1]);float area2 = (box2[2] - box2[0]) * (box2[3] - box2[1]);float union_area = area1 + area2 - intersection;float diou = intersection / union_area - dist_center * dist_center / (union_area * union_area);return diou;
}static void MulticlassNms(vector<vector<float>>& bboxes, const vector<vector<float>>& vaildBox, float nmsThr)
{for (auto &item : vaildBox) { /* score, xcenter, ycenter, w, h, classId */float boxXCenter = item[XCENTER_IDX];float boxYCenter = item[YCENTER_IDX];float boxWidth = item[W_IDX];float boxHeight = item[H_IDX];float x1 = (boxXCenter - boxWidth / 2);float y1 = (boxYCenter - boxHeight / 2);float x2 = (boxXCenter + boxWidth / 2);float y2 = (boxYCenter + boxHeight / 2);float area = (x2 - x1 + 1) * (y2 - y1 + 1);bool keep = true;vector<float> bbox {x1, y1, x2, y2, item[SCORE_IDX], item[CLSAA_ID_IDX], area};for (size_t j = 0; j < bboxes.size(); j++) {if (CalcDiou(bbox, bboxes[j]) > nmsThr) {keep = false;break;}}if (keep) {bboxes.push_back(bbox);}}
}
有讀者會有疑問,這里為什么不用CIOU_nms
,而用DIOU_nms
?
答:因為CIOU_loss
,是在DIOU_loss
的基礎上,添加的影響因子,包含groundtruth
標注框的信息,在訓練時用于回歸。
但在測試過程中,并沒有groundtruth
的信息,不用考慮影響因子,因此直接用DIOU_nms
即可。
參考文檔
https://blog.csdn.net/nan355655600/article/details/106246625