Skip to content

Commit d5e8792

Browse files
authored
Merge pull request opencv#17332 from l-bat:fix_nms
Fixed NMSBoxes bug * Added NMS for each class * Updated cpp sample * Fixed errors * Refactoring * Added NMS for IE
1 parent 5393185 commit d5e8792

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

samples/dnn/object_detection.cpp

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ std::vector<std::string> classes;
4545
inline void preprocess(const Mat& frame, Net& net, Size inpSize, float scale,
4646
const Scalar& mean, bool swapRB);
4747

48-
void postprocess(Mat& frame, const std::vector<Mat>& out, Net& net);
48+
void postprocess(Mat& frame, const std::vector<Mat>& out, Net& net, int backend);
4949

5050
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);
5151

@@ -148,7 +148,8 @@ int main(int argc, char** argv)
148148

149149
// Load a model.
150150
Net net = readNet(modelPath, configPath, parser.get<String>("framework"));
151-
net.setPreferableBackend(parser.get<int>("backend"));
151+
int backend = parser.get<int>("backend");
152+
net.setPreferableBackend(backend);
152153
net.setPreferableTarget(parser.get<int>("target"));
153154
std::vector<String> outNames = net.getUnconnectedOutLayersNames();
154155

@@ -245,7 +246,7 @@ int main(int argc, char** argv)
245246
std::vector<Mat> outs = predictionsQueue.get();
246247
Mat frame = processedFramesQueue.get();
247248

248-
postprocess(frame, outs, net);
249+
postprocess(frame, outs, net, backend);
249250

250251
if (predictionsQueue.counter > 1)
251252
{
@@ -285,7 +286,7 @@ int main(int argc, char** argv)
285286
std::vector<Mat> outs;
286287
net.forward(outs, outNames);
287288

288-
postprocess(frame, outs, net);
289+
postprocess(frame, outs, net, backend);
289290

290291
// Put efficiency information.
291292
std::vector<double> layersTimes;
@@ -319,7 +320,7 @@ inline void preprocess(const Mat& frame, Net& net, Size inpSize, float scale,
319320
}
320321
}
321322

322-
void postprocess(Mat& frame, const std::vector<Mat>& outs, Net& net)
323+
void postprocess(Mat& frame, const std::vector<Mat>& outs, Net& net, int backend)
323324
{
324325
static std::vector<int> outLayers = net.getUnconnectedOutLayers();
325326
static std::string outLayerType = net.getLayer(outLayers[0])->type;
@@ -396,11 +397,48 @@ void postprocess(Mat& frame, const std::vector<Mat>& outs, Net& net)
396397
else
397398
CV_Error(Error::StsNotImplemented, "Unknown output layer type: " + outLayerType);
398399

399-
std::vector<int> indices;
400-
NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
401-
for (size_t i = 0; i < indices.size(); ++i)
400+
// NMS is used inside Region layer only on DNN_BACKEND_OPENCV for another backends we need NMS in sample
401+
// or NMS is required if number of outputs > 1
402+
if (outLayers.size() > 1 || (outLayerType == "Region" && backend != DNN_BACKEND_OPENCV))
403+
{
404+
std::map<int, std::vector<size_t> > class2indices;
405+
for (size_t i = 0; i < classIds.size(); i++)
406+
{
407+
if (confidences[i] >= confThreshold)
408+
{
409+
class2indices[classIds[i]].push_back(i);
410+
}
411+
}
412+
std::vector<Rect> nmsBoxes;
413+
std::vector<float> nmsConfidences;
414+
std::vector<int> nmsClassIds;
415+
for (std::map<int, std::vector<size_t> >::iterator it = class2indices.begin(); it != class2indices.end(); ++it)
416+
{
417+
std::vector<Rect> localBoxes;
418+
std::vector<float> localConfidences;
419+
std::vector<size_t> classIndices = it->second;
420+
for (size_t i = 0; i < classIndices.size(); i++)
421+
{
422+
localBoxes.push_back(boxes[classIndices[i]]);
423+
localConfidences.push_back(confidences[classIndices[i]]);
424+
}
425+
std::vector<int> nmsIndices;
426+
NMSBoxes(localBoxes, localConfidences, confThreshold, nmsThreshold, nmsIndices);
427+
for (size_t i = 0; i < nmsIndices.size(); i++)
428+
{
429+
size_t idx = nmsIndices[i];
430+
nmsBoxes.push_back(localBoxes[idx]);
431+
nmsConfidences.push_back(localConfidences[idx]);
432+
nmsClassIds.push_back(it->first);
433+
}
434+
}
435+
boxes = nmsBoxes;
436+
classIds = nmsClassIds;
437+
confidences = nmsConfidences;
438+
}
439+
440+
for (size_t idx = 0; idx < boxes.size(); ++idx)
402441
{
403-
int idx = indices[i];
404442
Rect box = boxes[idx];
405443
drawPred(classIds[idx], confidences[idx], box.x, box.y,
406444
box.x + box.width, box.y + box.height, frame);

samples/dnn/object_detection.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,6 @@ def drawPred(classId, conf, left, top, right, bottom):
141141
# Network produces output blob with a shape NxC where N is a number of
142142
# detected objects and C is a number of classes + 4 where the first 4
143143
# numbers are [center_x, center_y, width, height]
144-
classIds = []
145-
confidences = []
146-
boxes = []
147144
for out in outs:
148145
for detection in out:
149146
scores = detection[5:]
@@ -163,9 +160,25 @@ def drawPred(classId, conf, left, top, right, bottom):
163160
print('Unknown output layer type: ' + lastLayer.type)
164161
exit()
165162

166-
indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)
163+
# NMS is used inside Region layer only on DNN_BACKEND_OPENCV for another backends we need NMS in sample
164+
# or NMS is required if number of outputs > 1
165+
if len(outNames) > 1 or lastLayer.type == 'Region' and args.backend != cv.dnn.DNN_BACKEND_OPENCV:
166+
indices = []
167+
classIds = np.array(classIds)
168+
boxes = np.array(boxes)
169+
confidences = np.array(confidences)
170+
unique_classes = set(classIds)
171+
for cl in unique_classes:
172+
class_indices = np.where(classIds == cl)[0]
173+
conf = confidences[class_indices]
174+
box = boxes[class_indices].tolist()
175+
nms_indices = cv.dnn.NMSBoxes(box, conf, confThreshold, nmsThreshold)
176+
nms_indices = nms_indices[:, 0] if len(nms_indices) else []
177+
indices.extend(class_indices[nms_indices])
178+
else:
179+
indices = np.arange(0, len(classIds))
180+
167181
for i in indices:
168-
i = i[0]
169182
box = boxes[i]
170183
left = box[0]
171184
top = box[1]

0 commit comments

Comments
 (0)