Add option for NMS for boxes with different labels#18891
Add option for NMS for boxes with different labels#18891alalek merged 4 commits intoopencv:masterfrom CowKeyMan:NMS_boxes_with_different_labels
Conversation
|
@sl-sergei Please take a look. |
|
@CowKeyMan Thanks for the patch. Could you add test for the new feature? |
|
@alalek Is it reasonable to rebase the solution to 3.4 or master branches? |
|
@CowKeyMan Thank you for contribution! I believe "master" branch should be OK (there is no such classes on 3.4 branch). Main question here is algorithm properties vs detection parameters. Good API should be abstract and simple (from User perspective). These control methods are expected: @dkurt @l-bat Please check naming. See #17570 for implementation details. P.S. Even |
|
@asmorkalov I have updated my PR with a test case I tried to put this into 'master' earlier. However, since it changes a function definiton (adding a new parameter, therefore changing the api), the Linux x64 build was failing |
|
The last build for Win64 OpenCL failed when I do not think it should have. Looking at the output it says that it was forcefully terminated with a SIGINT, is this of any concern? Should I do the setters and getters in this PR or should this be a separate PR after this one? |
| CV_OUT std::vector<float>& confidences, CV_OUT std::vector<Rect>& boxes, | ||
| float confThreshold = 0.5f, float nmsThreshold = 0.0f); | ||
| float confThreshold = 0.5f, float nmsThreshold = 0.0f, | ||
| bool nmsAcrossClasses = false); |
There was a problem hiding this comment.
Please make as a method:
CV_WRAP DetectionModel& setNMSAcrossClasses (bool value);Otherwise this method is too complicated.
There was a problem hiding this comment.
Hi, I'm doing this, however for when the return type is DetectionModel&, I get an error in the python binding that no default contructor for DetectionModel exists. It works fine when the type is void for the setter though.
There was a problem hiding this comment.
Yes, please take a look at Model class definition: https://github.com/opencv/opencv/blob/master/modules/dnn/include/opencv2/dnn/dnn.hpp
There was a problem hiding this comment.
Right, just saw the 'need to fix bindings first' comment. Does that mean I should leave it as void for now or create a default constructor for DetectionModel as well?
In the detect function in modules/dnn/include/opencv2/dnn/dnn.hpp, whose implementation can be found at modules/dnn/src/model.cpp, the Non Max Suppression (NMS) is applied only for objects of the same label. Thus, a flag was added with the purpose to allow developers to choose if they want to keep the default implementation or wether they would like NMS to be applied to all the boxes, regardless of label. The flag is called nmsDifferentLabels, and is given a default value of false, which applies the current default implementation, thus allowing existing projects to update opencv without disruption Solves issue #18832
|
@dkurt Thank you for your patience and guidance |
| * This function allows you to toggle this behaviour. | ||
| * @param[in] value The new value for nmsAcrossClasses | ||
| */ | ||
| CV_WRAP void setNmsAcrossClasses(bool value); |
There was a problem hiding this comment.
Please change return type:
void => DetectionModel& (return *this;)
to allow chains of .set*() calls.
(+ default dummy ctor DetectionModel() for bindings (see mentioned PR), + checks for nullptr impl from this ctor)
There was a problem hiding this comment.
Right, forgot about this. Would you be able to elaborate further what you mean by "checks for nullptr impl", please? In other words,
DetectionModel::DetectionModel() : Model()
{
// What goes here?
}
I understand the implementation field impl will be null in this constructor, but I am not sure what exactly to put here. I just updated this PR with a new commit to show the differences I made. I will change and squash it later once we rectify this.
For now, I made the constructor as CV_DEPRECATED_EXTERNAL, which is what the default constructor for Model is using at the moment and left the body empty, also to be like Model's, but am not sure if this is what you intended.
There was a problem hiding this comment.
Constructor is fine.
Need to add checks (CV_Assert()) into other methods (where impl is nullptr and impl.dynamicCast<DetectionModel_Impl>() is nullptr too).
There was a problem hiding this comment.
Added another commit with the assertions, is this what you meant? Also added the comments next to them, let me know if I should remove or reword
|
Awesome, thank you once again @alalek and @dkurt, as well as @asmorkalov |
…nt_labels Add option for NMS for boxes with different labels * DetectionModel impl * Add option for NMS for boxes with different labels In the detect function in modules/dnn/include/opencv2/dnn/dnn.hpp, whose implementation can be found at modules/dnn/src/model.cpp, the Non Max Suppression (NMS) is applied only for objects of the same label. Thus, a flag was added with the purpose to allow developers to choose if they want to keep the default implementation or wether they would like NMS to be applied to all the boxes, regardless of label. The flag is called nmsDifferentLabels, and is given a default value of false, which applies the current default implementation, thus allowing existing projects to update opencv without disruption Solves issue opencv#18832 * Change return type of set & Add default constr * Add assertions due to default constructor
In the detect function in modules/dnn/include/opencv2/dnn/dnn.hpp, whose implementation can be found at modules/dnn/src/model.cpp, the Non Max Suppression (NMS) is applied only for objects of the same label. Thus, a flag
was added with the purpose to allow developers to choose if they want to keep the default implementation or wether they would like NMS to be applied to all the boxes, regardless of label.
The flag is called nmsDifferentLabels, and is given a default value of false, which applies the current default implementation, thus allowing existing projects to update opencv without disruption
resolves #18832
The following image is from the MSCOCO dataset and the predictions were generated using YoloV4 trained on the MSCOCO dataset (weights here: https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights) . The numer '20' is the label for 'elephant' while the label '0' is the label for 'person'. You can see that the person and elephant have a very close bounding box, however they are not being suppressed when nmsDifferentLabels is False, but they are being suppressed when nmsDifferentLabels is True. You can also see that the box chosen was that with the highest confidence.
This is useful when an object is determined as 2 objects at once. In my case, I had some cars which were being classified as both a car and a truck at the same time, and I could not NMS them properly without adding more code. It was also difficult to find out why NMS was not behaving 'properly', leaving me to have to actually dig into the source code. This fixes this issue and in my opinion makes the code clearer without taking assumptions.
Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
Patch to opencv_extra has the same branch name.