#include <iostream>
static
void visualize(
Mat& input,
int frame,
Mat& faces,
double fps,
int thickness = 2)
{
std::string fpsString = cv::format("FPS : %.2f", (float)fps);
if (frame >= 0)
cout << "Frame " << frame << ", ";
cout << "FPS: " << fpsString << endl;
for (
int i = 0; i < faces.
rows; i++)
{
cout << "Face " << i
<<
", top-left coordinates: (" << faces.
at<
float>(i, 0) <<
", " << faces.
at<
float>(i, 1) <<
"), "
<<
"box width: " << faces.
at<
float>(i, 2) <<
", box height: " << faces.
at<
float>(i, 3) <<
", "
<<
"score: " << cv::format(
"%.2f", faces.
at<
float>(i, 14))
<< endl;
rectangle(input,
Rect2i(
int(faces.
at<
float>(i, 0)),
int(faces.
at<
float>(i, 1)),
int(faces.
at<
float>(i, 2)),
int(faces.
at<
float>(i, 3))),
Scalar(0, 255, 0), thickness);
circle(input,
Point2i(
int(faces.
at<
float>(i, 10)),
int(faces.
at<
float>(i, 11))), 2,
Scalar(255, 0, 255), thickness);
circle(input,
Point2i(
int(faces.
at<
float>(i, 12)),
int(faces.
at<
float>(i, 13))), 2,
Scalar(0, 255, 255), thickness);
}
}
int main(int argc, char** argv)
{
"{help h | | Print this message}"
"{image1 i1 | | Path to the input image1. Omit for detecting through VideoCapture}"
"{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}"
"{scale sc | 1.0 | Scale factor used to resize input video frames}"
"{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_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}"
"{nms_threshold | 0.3 | Suppress bounding boxes of iou >= nms_threshold}"
"{top_k | 5000 | Keep top_k bounding boxes before NMS}"
"{save s | false | Set true to save results. This flag is invalid when using camera}"
);
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
float scoreThreshold = parser.get<float>("score_threshold");
float nmsThreshold = parser.get<float>("nms_threshold");
int topK = parser.get<int>("top_k");
bool save = parser.get<bool>("save");
float scale = parser.get<
float>(
"scale");
double cosine_similar_thresh = 0.363;
double l2norm_similar_thresh = 1.128;
Ptr<FaceDetectorYN> detector = FaceDetectorYN::create(fd_modelPath,
"",
Size(320, 320), scoreThreshold, nmsThreshold, topK);
if (parser.has("image1"))
{
if (image1.empty())
{
std::cerr << "Cannot read image: " << input1 << std::endl;
return 2;
}
int imageWidth = int(image1.cols *
scale);
int imageHeight = int(image1.rows *
scale);
resize(image1, image1,
Size(imageWidth, imageHeight));
detector->setInputSize(image1.size());
detector->detect(image1, faces1);
{
std::cerr << "Cannot find a face in " << input1 << std::endl;
return 1;
}
visualize(image1, -1, faces1, tm.
getFPS());
if (save)
{
cout << "Saving result.jpg...\n";
}
if (parser.has("image2"))
{
if (image2.empty())
{
std::cerr << "Cannot read image2: " << input2 << std::endl;
return 2;
}
detector->setInputSize(image2.size());
detector->detect(image2, faces2);
{
std::cerr << "Cannot find a face in " << input2 << std::endl;
return 1;
}
visualize(image2, -1, faces2, tm.
getFPS());
if (save)
{
cout << "Saving result2.jpg...\n";
}
Mat aligned_face1, aligned_face2;
faceRecognizer->alignCrop(image1, faces1.
row(0), aligned_face1);
faceRecognizer->alignCrop(image2, faces2.
row(0), aligned_face2);
faceRecognizer->feature(aligned_face1, feature1);
feature1 = feature1.
clone();
faceRecognizer->feature(aligned_face2, feature2);
feature2 = feature2.
clone();
double cos_score = faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_COSINE);
double L2_score = faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_NORM_L2);
if (cos_score >= cosine_similar_thresh)
{
std::cout << "They have the same identity;";
}
else
{
std::cout << "They have different identities;";
}
std::cout << " Cosine Similarity: " << cos_score << ", threshold: " << cosine_similar_thresh << ". (higher value means higher similarity, max 1.0)\n";
if (L2_score <= l2norm_similar_thresh)
{
std::cout << "They have the same identity;";
}
else
{
std::cout << "They have different identities.";
}
std::cout << " NormL2 Distance: " << L2_score << ", threshold: " << l2norm_similar_thresh << ". (lower value means higher similarity, min 0.0)\n";
}
cout << "Press any key to exit..." << endl;
}
else
{
int frameWidth, frameHeight;
std::string video = parser.
get<
string>(
"video");
if (video.size() == 1 && isdigit(video[0]))
capture.
open(parser.get<
int>(
"video"));
else
{
cout << "Video " << video
<< ": width=" << frameWidth
<< ", height=" << frameHeight
<< endl;
}
else
{
cout << "Could not initialize video capturing: " << video << "\n";
return 1;
}
detector->setInputSize(
Size(frameWidth, frameHeight));
cout << "Press 'SPACE' to save frame, any other key to exit..." << endl;
int nFrame = 0;
for (;;)
{
if (!capture.
read(frame))
{
cerr << "Can't grab frame! Stop\n";
break;
}
resize(frame, frame,
Size(frameWidth, frameHeight));
detector->detect(frame, faces);
visualize(result, nFrame, faces, tm.
getFPS());
bool saveFrame = save;
if (key == ' ')
{
saveFrame = true;
key = 0;
}
if (saveFrame)
{
std::string frame_name = cv::format("frame_%05d.png", nFrame);
std::string result_name = cv::format("result_%05d.jpg", nFrame);
cout << "Saving '" << frame_name << "' and '" << result_name << "' ...\n";
}
++nFrame;
if (key > 0)
break;
}
cout << "Processed " << nFrame << " frames" << endl;
}
cout << "Done." << endl;
return 0;
}
Designed for command line parsing.
Definition: utility.hpp:818
n-dimensional dense array class
Definition: mat.hpp:811
CV_NODISCARD_STD Mat clone() const
Creates a full copy of the array and the underlying data.
Mat row(int y) const
Creates a matrix header for the specified matrix row.
_Tp & at(int i0=0)
Returns a reference to the specified array element.
int rows
the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
Definition: mat.hpp:2116
a Class to measure passing time.
Definition: utility.hpp:295
double getFPS() const
returns average FPS (frames per second) value.
Definition: utility.hpp:351
void start()
starts counting ticks.
Definition: utility.hpp:304
void stop()
stops counting ticks.
Definition: utility.hpp:310
void reset()
resets internal values.
Definition: utility.hpp:374
Class for video capturing from video files, image sequences or cameras.
Definition: videoio.hpp:683
virtual bool read(OutputArray image)
Grabs, decodes and returns the next video frame.
virtual bool open(const String &filename, int apiPreference=CAP_ANY)
Opens a video file or a capturing device or an IP video stream for video capturing.
virtual bool isOpened() const
Returns true if video capturing has been initialized already.
virtual double get(int propId) const
Returns the specified VideoCapture property.
Point_< int > Point2i
Definition: types.hpp:200
Point2i Point
Definition: types.hpp:204
std::string String
Definition: cvstd.hpp:152
Size2i Size
Definition: types.hpp:365
Scalar_< double > Scalar
Definition: types.hpp:691
std::shared_ptr< _Tp > Ptr
Definition: cvstd_wrapper.hpp:23
Rect_< int > Rect2i
Definition: types.hpp:481
cv::String findFile(const cv::String &relative_path, bool required=true, bool silentMode=false)
Try to find requested data file.
cv::String findFileOrKeep(const cv::String &relative_path, bool silentMode=false)
Definition: utility.hpp:1185
@ circle
Definition: gr_skig.hpp:62
void imshow(const String &winname, InputArray mat)
Displays an image in the specified window.
int waitKey(int delay=0)
Waits for a pressed key.
int pollKey()
Polls for a pressed key.
CV_EXPORTS_W bool imwrite(const String &filename, InputArray img, const std::vector< int > ¶ms=std::vector< int >())
Saves an image to a specified file.
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
Loads an image from a file.
void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
Draws a simple, thick, or filled up-right rectangle.
void putText(InputOutputArray img, const String &text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int lineType=LINE_8, bool bottomLeftOrigin=false)
Draws a text string.
@ FONT_HERSHEY_SIMPLEX
normal size sans-serif font
Definition: imgproc.hpp:868
@ CAP_PROP_FRAME_WIDTH
Width of the frames in the video stream.
Definition: videoio.hpp:138
@ CAP_PROP_FRAME_HEIGHT
Height of the frames in the video stream.
Definition: videoio.hpp:139
void scale(cv::Mat &mat, const cv::Mat &range, const T min, const T max)
Definition: quality_utils.hpp:90
"black box" representation of the file storage associated with a file on disk.
Definition: core.hpp:106