前两天自己实现了人脸识别的C 程序,具体可见:
人脸识别从0到1之完美实现
今天研究了OpenCV的人脸识别源码,经改动及调试可用于简单场景。
源码部署在/samples/cpp/。。。。。。。。。。。。。
图片人脸检测:/samples/cpp/facial_features.cpp
代码语言:javascript复制/*
* Author: Samyak Datta (datta[dot]samyak[at]gmail.com)
*
* A program to detect facial feature points using
* Haarcascade classifiers for face, eyes, nose and mouth
*
*/
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;
// Functions for facial feature detection
static void help();
static void detectFaces(Mat&, vector<Rect_<int> >&, string);
static void detectEyes(Mat&, vector<Rect_<int> >&, string);
static void detectNose(Mat&, vector<Rect_<int> >&, string);
static void detectMouth(Mat&, vector<Rect_<int> >&, string);
static void detectFacialFeaures(Mat&, const vector<Rect_<int> >, string, string, string);
string input_image_path;
string face_cascade_path, eye_cascade_path, nose_cascade_path, mouth_cascade_path;
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv,
"{@image||}{@facexml||}{@eyexml||}{nose||}{mouth||}{help h||}");
if (parser.has("help"))
{
help();
return 0;
}
input_image_path = parser.get<string>("@image");
face_cascade_path = parser.get<string>("@facexml");
// eye_cascade_path = parser.has("eyes") ? parser.get<string>("eyes") : "";
eye_cascade_path = parser.get<string>("@eyexml");
nose_cascade_path = parser.has("nose") ? parser.get<string>("nose") : "";
mouth_cascade_path = parser.has("mouth") ? parser.get<string>("mouth") : "";
if (input_image_path.empty() || face_cascade_path.empty())
{
cout << "IMAGE or FACE_CASCADE are not specified";
return 1;
}
// Load image and cascade classifier files
Mat image;
image = imread(input_image_path);
// Detect faces and facial features
vector<Rect_<int> > faces;
detectFaces(image, faces, face_cascade_path);
detectFacialFeaures(image, faces, eye_cascade_path, nose_cascade_path, mouth_cascade_path);
imshow("Result", image);
waitKey(0);
return 0;
}
static void help()
{
cout << "nThis file demonstrates facial feature points detection using Haarcascade classifiers.n"
"The program detects a face and eyes, nose and mouth inside the face."
"The code has been tested on the Japanese Female Facial Expression (JAFFE) database and found"
"to give reasonably accurate results. n";
cout << "nUSAGE: ./cpp-example-facial_features [IMAGE] [FACE_CASCADE] [OPTIONS]n"
"IMAGEntPath to the image of a face taken as input.n"
"FACE_CASCSDEnt Path to a haarcascade classifier for face detection.n"
"OPTIONS: nThere are 3 options available which are described in detail. There must be a "
"space between the option and it's argument (All three options accept arguments).n"
"t-eyes=<eyes_cascade> : Specify the haarcascade classifier for eye detection.n"
"t-nose=<nose_cascade> : Specify the haarcascade classifier for nose detection.n"
"t-mouth=<mouth-cascade> : Specify the haarcascade classifier for mouth detection.n";
cout << "EXAMPLE:n"
"(1) ./cpp-example-facial_features image.jpg face.xml -eyes=eyes.xml -mouth=mouth.xmln"
"tThis will detect the face, eyes and mouth in image.jpg.n"
"(2) ./cpp-example-facial_features image.jpg face.xml -nose=nose.xmln"
"tThis will detect the face and nose in image.jpg.n"
"(3) ./cpp-example-facial_features image.jpg face.xmln"
"tThis will detect only the face in image.jpg.n";
cout << " nnThe classifiers for face and eyes can be downloaded from : "
" nhttps://github.com/opencv/opencv/tree/master/data/haarcascades";
cout << "nnThe classifiers for nose and mouth can be downloaded from : "
" nhttps://github.com/opencv/opencv_contrib/tree/master/modules/face/data/cascadesn";
}
static void detectFaces(Mat& img, vector<Rect_<int> >& faces, string cascade_path)
{
CascadeClassifier face_cascade;
face_cascade.load(cascade_path);
if (!face_cascade.empty())
face_cascade.detectMultiScale(img, faces, 1.15, 3, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectFacialFeaures(Mat& img, const vector<Rect_<int> > faces, string eye_cascade,
string nose_cascade, string mouth_cascade)
{
for(unsigned int i = 0; i < faces.size(); i)
{
// Mark the bounding box enclosing the face
Rect face = faces[i];
rectangle(img, Point(face.x, face.y), Point(face.x face.width, face.y face.height),
Scalar(255, 0, 0), 1, 4);
// Eyes, nose and mouth will be detected inside the face (region of interest)
Mat ROI = img(Rect(face.x, face.y, face.width, face.height));
// Check if all features (eyes, nose and mouth) are being detected
bool is_full_detection = false;
if( (!eye_cascade.empty()) && (!nose_cascade.empty()) && (!mouth_cascade.empty()) )
is_full_detection = true;
// Detect eyes if classifier provided by the user
if(!eye_cascade.empty())
{
vector<Rect_<int> > eyes;
detectEyes(ROI, eyes, eye_cascade);
// Mark points corresponding to the centre of the eyes
for(unsigned int j = 0; j < eyes.size(); j)
{
Rect e = eyes[j];
circle(ROI, Point(e.x e.width/2, e.y e.height/2), 3, Scalar(0, 255, 0), -1, 8);
/* rectangle(ROI, Point(e.x, e.y), Point(e.x e.width, e.y e.height),
Scalar(0, 255, 0), 1, 4); */
}
}
// Detect nose if classifier provided by the user
double nose_center_height = 0.0;
if(!nose_cascade.empty())
{
vector<Rect_<int> > nose;
detectNose(ROI, nose, nose_cascade);
// Mark points corresponding to the centre (tip) of the nose
for(unsigned int j = 0; j < nose.size(); j)
{
Rect n = nose[j];
circle(ROI, Point(n.x n.width/2, n.y n.height/2), 3, Scalar(0, 255, 0), -1, 8);
nose_center_height = (n.y n.height/2);
}
}
// Detect mouth if classifier provided by the user
double mouth_center_height = 0.0;
if(!mouth_cascade.empty())
{
vector<Rect_<int> > mouth;
detectMouth(ROI, mouth, mouth_cascade);
for(unsigned int j = 0; j < mouth.size(); j)
{
Rect m = mouth[j];
mouth_center_height = (m.y m.height/2);
// The mouth should lie below the nose
if( (is_full_detection) && (mouth_center_height > nose_center_height) )
{
rectangle(ROI, Point(m.x, m.y), Point(m.x m.width, m.y m.height), Scalar(0, 255, 0), 1, 4);
}
else if( (is_full_detection) && (mouth_center_height <= nose_center_height) )
continue;
else
rectangle(ROI, Point(m.x, m.y), Point(m.x m.width, m.y m.height), Scalar(0, 255, 0), 1, 4);
}
}
}
return;
}
static void detectEyes(Mat& img, vector<Rect_<int> >& eyes, string cascade_path)
{
CascadeClassifier eyes_cascade;
eyes_cascade.load(cascade_path);
if (!eyes_cascade.empty())
eyes_cascade.detectMultiScale(img, eyes, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectNose(Mat& img, vector<Rect_<int> >& nose, string cascade_path)
{
CascadeClassifier nose_cascade;
nose_cascade.load(cascade_path);
if (!nose_cascade.empty())
nose_cascade.detectMultiScale(img, nose, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectMouth(Mat& img, vector<Rect_<int> >& mouth, string cascade_path)
{
CascadeClassifier mouth_cascade;
mouth_cascade.load(cascade_path);
if (!mouth_cascade.empty())
mouth_cascade.detectMultiScale(img, mouth, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
较之前实现有点复杂人脸识别初探之人脸检测(一)
同时,人脸识别源码经改动及调试成功如下:
samples/cpp/tutorial_code/objectDetection/objectDetection.cpp
代码语言:javascript复制#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace std;
using namespace cv;
/** Function Headers */
void detectAndDisplay( Mat frame );
/** Global variables */
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
/** @function main */
int main( int argc, const char** argv )
{
/* CommandLineParser parser(argc, argv,
"{help h||}"
"{face_cascade|data/haarcascades/haarcascade_frontalface_alt.xml|Path to face cascade.}"
"{eyes_cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|Path to eyes cascade.}"
"{camera|0|Camera device number.}");
*/
cv::CommandLineParser parser(argc, argv,
"{@facexml||}{@eyexml||}{@camera||}");
parser.about( "nThis program demonstrates using the cv::CascadeClassifier class to detect objects (Face eyes) in a video stream.n"
"You can use Haar or LBP features.nn" );
parser.printMessage();
// string face_cascade_name = parser.get<string >("face_cascade") ;
//string eyes_cascade_name = parser.get<string >("eyes_cascade") ;
string face_cascade_name = parser.get<string>("@facexml");
string eyes_cascade_name = parser.get<string >("@eyexml") ;
//-- 1. Load the cascades
if( !face_cascade.load( face_cascade_name ) )
{
cout << "--(!)Error loading face cascaden";
return -1;
};
if( !eyes_cascade.load( eyes_cascade_name ) )
{
cout << "--(!)Error loading eyes cascaden";
return -1;
};
//int camera_device = parser.get<int>("@camera");
string camera_device = parser.get<string>("@camera");
VideoCapture capture;
//-- 2. Read the video stream
capture.open( camera_device );
if ( ! capture.isOpened() )
{
cout << "--(!)Error opening video capturen";
return -1;
}
Mat frame;
while ( capture.read(frame) )
{
if( frame.empty() )
{
cout << "--(!) No captured frame -- Break!n";
break;
}
//-- 3. Apply the classifier to the frame
detectAndDisplay( frame );
if( waitKey(10) == 27 )
{
break; // escape
}
}
return 0;
}
/** @function detectAndDisplay */
void detectAndDisplay( Mat frame )
{
Mat frame_gray;
cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
std::vector<Rect> faces;
face_cascade.detectMultiScale( frame_gray, faces );
for ( size_t i = 0; i < faces.size(); i )
{
Point center( faces[i].x faces[i].width/2, faces[i].y faces[i].height/2 );
ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );
Mat faceROI = frame_gray( faces[i] );
//-- In each face, detect eyes
std::vector<Rect> eyes;
eyes_cascade.detectMultiScale( faceROI, eyes );
for ( size_t j = 0; j < eyes.size(); j )
{
Point eye_center( faces[i].x eyes[j].x eyes[j].width/2, faces[i].y eyes[j].y eyes[j].height/2 );
int radius = cvRound( (eyes[j].width eyes[j].height)*0.25 );
circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4 );
}
}
//-- Show what you got
imshow( "Capture - Face detection", frame );
}
同时看到了,打开摄像头进行捕获视频的源码:
samples/cpp/example_cmake/example.cpp
代码语言:javascript复制#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void drawText(Mat & image);
int main()
{
cout << "Built with OpenCV " << CV_VERSION << endl;
Mat image;
VideoCapture capture;
capture.open(0);
if(capture.isOpened())
{
cout << "Capture is opened" << endl;
for(;;)
{
capture >> image;
if(image.empty())
break;
drawText(image);
imshow("Sample", image);
if(waitKey(10) >= 0)
break;
}
}
else
{
cout << "No capture" << endl;
image = Mat::zeros(480, 640, CV_8UC1);
drawText(image);
imshow("Sample", image);
waitKey(0);
}
return 0;
}
void drawText(Mat & image)
{
putText(image, "Hello OpenCV",
Point(20, 50),
FONT_HERSHEY_COMPLEX, 1, // font face and scale
Scalar(255, 255, 255), // white
1, LINE_AA); // line thickness and type
}
较之前规范些OpenCV打开免驱摄像头并进行简单操作
对应的:
代码语言:javascript复制# cmake needs this line
cmake_minimum_required(VERSION 3.1)
# Enable C 11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
# Define project name
project(opencv_example_project)
# Find OpenCV, you may need to set OpenCV_DIR variable
# to the absolute path to the directory containing OpenCVConfig.cmake file
# via the command line or GUI
find_package(OpenCV REQUIRED)
# If the package has been found, several variables will
# be set, you can find the full list with descriptions
# in the OpenCVConfig.cmake file.
# Print some message showing some of them
message(STATUS "OpenCV library status:")
message(STATUS " config: ${OpenCV_DIR}")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
# Declare the executable target built from your sources
add_executable(opencv_example example.cpp)
# Link your application with OpenCV libraries
target_link_libraries(opencv_example PRIVATE ${OpenCV_LIBS})
至此,人脸识别告一段落,接下来继续公布其余项目源码
OpenCV即时上手可学习可商用的项目