Merge pull request #21409 from sturkmen72:patch-3

pull/21432/head
Alexander Alekhin 3 years ago
commit 6fd1a2ef52
  1. 14
      doc/tutorials/dnn/dnn_face/dnn_face.markdown
  2. 45
      modules/objdetect/include/opencv2/objdetect.hpp
  3. 4
      modules/objdetect/include/opencv2/objdetect/detection_based_tracker.hpp
  4. 21
      modules/objdetect/include/opencv2/objdetect/face.hpp
  5. 9
      samples/dnn/face_detect.cpp
  6. 10
      samples/dnn/face_detect.py

@ -8,19 +8,19 @@
| | | | | |
| -: | :- | | -: | :- |
| Original Author | Chengrui Wang, Yuantao Feng | | Original Author | Chengrui Wang, Yuantao Feng |
| Compatibility | OpenCV >= 4.5.1 | | Compatibility | OpenCV >= 4.5.4 |
## Introduction ## Introduction
In this section, we introduce the DNN-based module for face detection and face recognition. Models can be obtained in [Models](#Models). The usage of `FaceDetectorYN` and `FaceRecognizerSF` are presented in [Usage](#Usage). In this section, we introduce cv::FaceDetectorYN class for face detection and cv::FaceRecognizerSF class for face recognition.
## Models ## Models
There are two models (ONNX format) pre-trained and required for this module: There are two models (ONNX format) pre-trained and required for this module:
- [Face Detection](https://github.com/ShiqiYu/libfacedetection.train/tree/master/tasks/task1/onnx): - [Face Detection](https://github.com/opencv/opencv_zoo/tree/master/models/face_detection_yunet):
- Size: 337KB - Size: 338KB
- Results on WIDER Face Val set: 0.830(easy), 0.824(medium), 0.708(hard) - Results on WIDER Face Val set: 0.830(easy), 0.824(medium), 0.708(hard)
- [Face Recognition](https://drive.google.com/file/d/1ClK9WiB492c5OZFKveF3XiHCejoOxINW/view?usp=sharing) - [Face Recognition](https://github.com/opencv/opencv_zoo/tree/master/models/face_recognition_sface)
- Size: 36.9MB - Size: 36.9MB
- Results: - Results:
@ -32,9 +32,7 @@ There are two models (ONNX format) pre-trained and required for this module:
| AgeDB-30 | 94.90% | 1.202 | 0.277 | | AgeDB-30 | 94.90% | 1.202 | 0.277 |
| CFP-FP | 94.80% | 1.253 | 0.212 | | CFP-FP | 94.80% | 1.253 | 0.212 |
## Usage ## Code
### DNNFaceDetector
@add_toggle_cpp @add_toggle_cpp
- **Downloadable code**: Click - **Downloadable code**: Click

@ -49,8 +49,8 @@
/** /**
@defgroup objdetect Object Detection @defgroup objdetect Object Detection
Haar Feature-based Cascade Classifier for Object Detection @{
---------------------------------------------------------- @defgroup objdetect_cascade_classifier Cascade Classifier for Object Detection
The object detector described below has been initially proposed by Paul Viola @cite Viola01 and The object detector described below has been initially proposed by Paul Viola @cite Viola01 and
improved by Rainer Lienhart @cite Lienhart02 . improved by Rainer Lienhart @cite Lienhart02 .
@ -90,8 +90,7 @@ middle) and the sum of the image pixels under the black stripe multiplied by 3 i
compensate for the differences in the size of areas. The sums of pixel values over a rectangular compensate for the differences in the size of areas. The sums of pixel values over a rectangular
regions are calculated rapidly using integral images (see below and the integral description). regions are calculated rapidly using integral images (see below and the integral description).
To see the object detector at work, have a look at the facedetect demo: Check @ref tutorial_cascade_classifier "the corresponding tutorial" for more details.
<https://github.com/opencv/opencv/tree/4.x/samples/cpp/dbt_face_detection.cpp>
The following reference is for the detection part only. There is a separate application called The following reference is for the detection part only. There is a separate application called
opencv_traincascade that can train a cascade of boosted classifiers from a set of samples. opencv_traincascade that can train a cascade of boosted classifiers from a set of samples.
@ -99,10 +98,13 @@ opencv_traincascade that can train a cascade of boosted classifiers from a set o
@note In the new C++ interface it is also possible to use LBP (local binary pattern) features in @note In the new C++ interface it is also possible to use LBP (local binary pattern) features in
addition to Haar-like features. .. [Viola01] Paul Viola and Michael J. Jones. Rapid Object Detection addition to Haar-like features. .. [Viola01] Paul Viola and Michael J. Jones. Rapid Object Detection
using a Boosted Cascade of Simple Features. IEEE CVPR, 2001. The paper is available online at using a Boosted Cascade of Simple Features. IEEE CVPR, 2001. The paper is available online at
<http://research.microsoft.com/en-us/um/people/viola/Pubs/Detect/violaJones_CVPR2001.pdf> <https://github.com/SvHey/thesis/blob/master/Literature/ObjectDetection/violaJones_CVPR2001.pdf>
@{ @defgroup objdetect_hog HOG (Histogram of Oriented Gradients) descriptor and object detector
@defgroup objdetect_c C API @defgroup objdetect_qrcode QRCode detection and encoding
@defgroup objdetect_dnn_face DNN-based face detection and recognition
Check @ref tutorial_dnn_face "the corresponding tutorial" for more details.
@defgroup objdetect_common Common functions and classes
@} @}
*/ */
@ -111,13 +113,15 @@ typedef struct CvHaarClassifierCascade CvHaarClassifierCascade;
namespace cv namespace cv
{ {
//! @addtogroup objdetect //! @addtogroup objdetect_common
//! @{ //! @{
///////////////////////////// Object Detection //////////////////////////// ///////////////////////////// Object Detection ////////////////////////////
//! class for grouping object candidates, detected by Cascade Classifier, HOG etc. /** @brief This class is used for grouping object candidates detected by Cascade Classifier, HOG etc.
//! instance of the class is to be passed to cv::partition (see cxoperations.hpp)
instance of the class is to be passed to cv::partition
*/
class CV_EXPORTS SimilarRects class CV_EXPORTS SimilarRects
{ {
public: public:
@ -162,6 +166,10 @@ CV_EXPORTS void groupRectangles(std::vector<Rect>& rectList, std::vector<int>&
CV_EXPORTS void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>& foundWeights, CV_EXPORTS void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>& foundWeights,
std::vector<double>& foundScales, std::vector<double>& foundScales,
double detectThreshold = 0.0, Size winDetSize = Size(64, 128)); double detectThreshold = 0.0, Size winDetSize = Size(64, 128));
//! @}
//! @addtogroup objdetect_cascade_classifier
//! @{
template<> struct DefaultDeleter<CvHaarClassifierCascade>{ CV_EXPORTS void operator ()(CvHaarClassifierCascade* obj) const; }; template<> struct DefaultDeleter<CvHaarClassifierCascade>{ CV_EXPORTS void operator ()(CvHaarClassifierCascade* obj) const; };
@ -243,7 +251,7 @@ public:
CV_WRAP bool load( const String& filename ); CV_WRAP bool load( const String& filename );
/** @brief Reads a classifier from a FileStorage node. /** @brief Reads a classifier from a FileStorage node.
@note The file may contain a new cascade classifier (trained traincascade application) only. @note The file may contain a new cascade classifier (trained by the traincascade application) only.
*/ */
CV_WRAP bool read( const FileNode& node ); CV_WRAP bool read( const FileNode& node );
@ -260,12 +268,6 @@ public:
cvHaarDetectObjects. It is not used for a new cascade. cvHaarDetectObjects. It is not used for a new cascade.
@param minSize Minimum possible object size. Objects smaller than that are ignored. @param minSize Minimum possible object size. Objects smaller than that are ignored.
@param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale. @param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale.
The function is parallelized with the TBB library.
@note
- (Python) A face detection example using cascade classifiers can be found at
opencv_source_code/samples/python/facedetect.py
*/ */
CV_WRAP void detectMultiScale( InputArray image, CV_WRAP void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects, CV_OUT std::vector<Rect>& objects,
@ -338,7 +340,10 @@ public:
}; };
CV_EXPORTS Ptr<BaseCascadeClassifier::MaskGenerator> createFaceDetectionMaskGenerator(); CV_EXPORTS Ptr<BaseCascadeClassifier::MaskGenerator> createFaceDetectionMaskGenerator();
//! @}
//! @addtogroup objdetect_hog
//! @{
//////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector ////////////// //////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector //////////////
//! struct for detection region of interest (ROI) //! struct for detection region of interest (ROI)
@ -666,6 +671,10 @@ public:
*/ */
void groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& weights, int groupThreshold, double eps) const; void groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& weights, int groupThreshold, double eps) const;
}; };
//! @}
//! @addtogroup objdetect_qrcode
//! @{
class CV_EXPORTS_W QRCodeEncoder { class CV_EXPORTS_W QRCodeEncoder {
protected: protected:
@ -827,7 +836,7 @@ protected:
Ptr<Impl> p; Ptr<Impl> p;
}; };
//! @} objdetect //! @}
} }
#include "opencv2/objdetect/detection_based_tracker.hpp" #include "opencv2/objdetect/detection_based_tracker.hpp"

@ -51,7 +51,7 @@
namespace cv namespace cv
{ {
//! @addtogroup objdetect //! @addtogroup objdetect_cascade_classifier
//! @{ //! @{
class CV_EXPORTS DetectionBasedTracker class CV_EXPORTS DetectionBasedTracker
@ -215,7 +215,7 @@ class CV_EXPORTS DetectionBasedTracker
void detectInRegion(const cv::Mat& img, const cv::Rect& r, std::vector<cv::Rect>& detectedObjectsInRegions); void detectInRegion(const cv::Mat& img, const cv::Rect& r, std::vector<cv::Rect>& detectedObjectsInRegions);
}; };
//! @} objdetect //! @}
} //end of cv namespace } //end of cv namespace

@ -7,13 +7,15 @@
#include <opencv2/core.hpp> #include <opencv2/core.hpp>
/** @defgroup dnn_face DNN-based face detection and recognition
*/
namespace cv namespace cv
{ {
/** @brief DNN-based face detector, model download link: https://github.com/ShiqiYu/libfacedetection.train/tree/master/tasks/task1/onnx. //! @addtogroup objdetect_dnn_face
//! @{
/** @brief DNN-based face detector
model download link: https://github.com/opencv/opencv_zoo/tree/master/models/face_detection_yunet
*/ */
class CV_EXPORTS_W FaceDetectorYN class CV_EXPORTS_W FaceDetectorYN
{ {
@ -80,7 +82,9 @@ public:
int target_id = 0); int target_id = 0);
}; };
/** @brief DNN-based face recognizer, model download link: https://drive.google.com/file/d/1ClK9WiB492c5OZFKveF3XiHCejoOxINW/view. /** @brief DNN-based face recognizer
model download link: https://github.com/opencv/opencv_zoo/tree/master/models/face_recognition_sface
*/ */
class CV_EXPORTS_W FaceRecognizerSF class CV_EXPORTS_W FaceRecognizerSF
{ {
@ -105,11 +109,11 @@ public:
CV_WRAP virtual void feature(InputArray aligned_img, OutputArray face_feature) = 0; CV_WRAP virtual void feature(InputArray aligned_img, OutputArray face_feature) = 0;
/** @brief Calculating the distance between two face features /** @brief Calculating the distance between two face features
* @param _face_feature1 the first input feature * @param face_feature1 the first input feature
* @param _face_feature2 the second input feature of the same size and the same type as _face_feature1 * @param face_feature2 the second input feature of the same size and the same type as face_feature1
* @param dis_type defining the similarity with optional values "FR_OSINE" or "FR_NORM_L2" * @param dis_type defining the similarity with optional values "FR_OSINE" or "FR_NORM_L2"
*/ */
CV_WRAP virtual double match(InputArray _face_feature1, InputArray _face_feature2, int dis_type = FaceRecognizerSF::FR_COSINE) const = 0; CV_WRAP virtual double match(InputArray face_feature1, InputArray face_feature2, int dis_type = FaceRecognizerSF::FR_COSINE) const = 0;
/** @brief Creates an instance of this class with given parameters /** @brief Creates an instance of this class with given parameters
* @param model the path of the onnx model used for face recognition * @param model the path of the onnx model used for face recognition
@ -120,6 +124,7 @@ public:
CV_WRAP static Ptr<FaceRecognizerSF> create(const String& model, const String& config, int backend_id = 0, int target_id = 0); CV_WRAP static Ptr<FaceRecognizerSF> create(const String& model, const String& config, int backend_id = 0, int target_id = 0);
}; };
//! @}
} // namespace cv } // namespace cv
#endif #endif

@ -44,8 +44,8 @@ int main(int argc, char** argv)
"{image2 i2 | | Path to the input image2. When image1 and image2 parameters given then the program try to find a face on both images and runs face recognition algorithm}" "{image2 i2 | | Path to the input image2. When image1 and image2 parameters given then the program try to find a face on both images and runs face recognition algorithm}"
"{video v | 0 | Path to the input video}" "{video v | 0 | Path to the input video}"
"{scale sc | 1.0 | Scale factor used to resize input video frames}" "{scale sc | 1.0 | Scale factor used to resize input video frames}"
"{fd_model fd | yunet.onnx | Path to the model. Download yunet.onnx in https://github.com/ShiqiYu/libfacedetection.train/tree/master/tasks/task1/onnx }" "{fd_model fd | face_detection_yunet_2021dec.onnx| Path to the model. Download yunet.onnx in https://github.com/opencv/opencv_zoo/tree/master/models/face_detection_yunet}"
"{fr_model fr | face_recognizer_fast.onnx | Path to the face recognition model. Download the model at https://drive.google.com/file/d/1ClK9WiB492c5OZFKveF3XiHCejoOxINW/view}" "{fr_model fr | face_recognition_sface_2021dec.onnx | Path to the face recognition model. Download the model at https://github.com/opencv/opencv_zoo/tree/master/models/face_recognition_sface}"
"{score_threshold | 0.9 | Filter out faces of score < score_threshold}" "{score_threshold | 0.9 | Filter out faces of score < score_threshold}"
"{nms_threshold | 0.3 | Suppress bounding boxes of iou >= nms_threshold}" "{nms_threshold | 0.3 | Suppress bounding boxes of iou >= nms_threshold}"
"{top_k | 5000 | Keep top_k bounding boxes before NMS}" "{top_k | 5000 | Keep top_k bounding boxes before NMS}"
@ -65,6 +65,7 @@ int main(int argc, char** argv)
int topK = parser.get<int>("top_k"); int topK = parser.get<int>("top_k");
bool save = parser.get<bool>("save"); bool save = parser.get<bool>("save");
float scale = parser.get<float>("scale");
double cosine_similar_thresh = 0.363; double cosine_similar_thresh = 0.363;
double l2norm_similar_thresh = 1.128; double l2norm_similar_thresh = 1.128;
@ -87,6 +88,9 @@ int main(int argc, char** argv)
return 2; return 2;
} }
int imageWidth = int(image1.cols * scale);
int imageHeight = int(image1.rows * scale);
resize(image1, image1, Size(imageWidth, imageHeight));
tm.start(); tm.start();
//! [inference] //! [inference]
@ -199,7 +203,6 @@ int main(int argc, char** argv)
else else
{ {
int frameWidth, frameHeight; int frameWidth, frameHeight;
float scale = parser.get<float>("scale");
VideoCapture capture; VideoCapture capture;
std::string video = parser.get<string>("video"); std::string video = parser.get<string>("video");
if (video.size() == 1 && isdigit(video[0])) if (video.size() == 1 && isdigit(video[0]))

@ -16,8 +16,8 @@ parser.add_argument('--image1', '-i1', type=str, help='Path to the input image1.
parser.add_argument('--image2', '-i2', type=str, help='Path to the input image2. When image1 and image2 parameters given then the program try to find a face on both images and runs face recognition algorithm.') parser.add_argument('--image2', '-i2', type=str, help='Path to the input image2. When image1 and image2 parameters given then the program try to find a face on both images and runs face recognition algorithm.')
parser.add_argument('--video', '-v', type=str, help='Path to the input video.') parser.add_argument('--video', '-v', type=str, help='Path to the input video.')
parser.add_argument('--scale', '-sc', type=float, default=1.0, help='Scale factor used to resize input video frames.') parser.add_argument('--scale', '-sc', type=float, default=1.0, help='Scale factor used to resize input video frames.')
parser.add_argument('--face_detection_model', '-fd', type=str, default='yunet.onnx', help='Path to the face detection model. Download the model at https://github.com/ShiqiYu/libfacedetection.train/tree/master/tasks/task1/onnx.') parser.add_argument('--face_detection_model', '-fd', type=str, default='face_detection_yunet_2021dec.onnx', help='Path to the face detection model. Download the model at https://github.com/opencv/opencv_zoo/tree/master/models/face_detection_yunet')
parser.add_argument('--face_recognition_model', '-fr', type=str, default='face_recognizer_fast.onnx', help='Path to the face recognition model. Download the model at https://drive.google.com/file/d/1ClK9WiB492c5OZFKveF3XiHCejoOxINW/view.') parser.add_argument('--face_recognition_model', '-fr', type=str, default='face_recognition_sface_2021dec.onnx', help='Path to the face recognition model. Download the model at https://github.com/opencv/opencv_zoo/tree/master/models/face_recognition_sface')
parser.add_argument('--score_threshold', type=float, default=0.9, help='Filtering out faces of score < score_threshold.') parser.add_argument('--score_threshold', type=float, default=0.9, help='Filtering out faces of score < score_threshold.')
parser.add_argument('--nms_threshold', type=float, default=0.3, help='Suppress bounding boxes of iou >= nms_threshold.') parser.add_argument('--nms_threshold', type=float, default=0.3, help='Suppress bounding boxes of iou >= nms_threshold.')
parser.add_argument('--top_k', type=int, default=5000, help='Keep top_k bounding boxes before NMS.') parser.add_argument('--top_k', type=int, default=5000, help='Keep top_k bounding boxes before NMS.')
@ -56,11 +56,15 @@ if __name__ == '__main__':
# If input is an image # If input is an image
if args.image1 is not None: if args.image1 is not None:
img1 = cv.imread(cv.samples.findFile(args.image1)) img1 = cv.imread(cv.samples.findFile(args.image1))
img1Width = int(img1.shape[1]*args.scale)
img1Height = int(img1.shape[0]*args.scale)
img1 = cv.resize(img1, (img1Width, img1Height))
tm.start() tm.start()
## [inference] ## [inference]
# Set input size before inference # Set input size before inference
detector.setInputSize((img1.shape[1], img1.shape[0])) detector.setInputSize((img1Width, img1Height))
faces1 = detector.detect(img1) faces1 = detector.detect(img1)
## [inference] ## [inference]

Loading…
Cancel
Save