Merge pull request #2154 from LaurentBerger:py_face_landmark

pull/2169/head^2
Alexander Alekhin 5 years ago
commit 84c882d058
  1. 4
      modules/face/include/opencv2/face/facemark.hpp
  2. 2
      modules/face/include/opencv2/face/facemarkAAM.hpp
  3. 29
      modules/face/samples/landmarks_demo.py
  4. 2
      modules/face/src/face_alignmentimpl.hpp
  5. 49
      modules/face/src/facemarkAAM.cpp
  6. 45
      modules/face/src/facemarkLBF.cpp
  7. 45
      modules/face/src/getlandmarks.cpp

@ -74,8 +74,8 @@ public:
@endcode
*/
CV_WRAP virtual bool fit( InputArray image,
const std::vector<Rect>& faces,
CV_OUT std::vector<std::vector<Point2f> >& landmarks ) = 0;
InputArray faces,
OutputArrayOfArrays landmarks) = 0;
}; /* Facemark*/

@ -146,7 +146,7 @@ public:
};
//! overload with additional Config structures
virtual bool fitConfig( InputArray image, const std::vector<Rect>& roi, std::vector<std::vector<Point2f> >& _landmarks, const std::vector<Config> &runtime_params ) = 0;
virtual bool fitConfig( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks, const std::vector<Config> &runtime_params ) = 0;
//! initializer

@ -0,0 +1,29 @@
import random
import numpy as np
import cv2 as cv
frame1 = cv.imread(cv.samples.findFile('lena.jpg'))
if frame1 is None:
print("image not found")
exit()
frame = np.vstack((frame1,frame1))
facemark = cv.face.createFacemarkLBF()
try:
facemark.loadModel(cv.samples.findFile('lbfmodel.yaml'))
except cv.error:
print("Model not found\nlbfmodel.yaml can be download at")
print("https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml")
cascade = cv.CascadeClassifier(cv.samples.findFile('lbpcascade_frontalface_improved.xml'))
if cascade.empty() :
print("cascade not found")
exit()
faces = cascade.detectMultiScale(frame, 1.05, 3, cv.CASCADE_SCALE_IMAGE, (30, 30))
ok, landmarks = facemark.fit(frame, faces=faces)
cv.imshow("Image", frame)
for marks in landmarks:
couleur = (random.randint(0,255),
random.randint(0,255),
random.randint(0,255))
cv.face.drawFacemarks(frame, marks, couleur)
cv.imshow("Image Landmarks", frame)
cv.waitKey()

@ -73,7 +73,7 @@ public:
void loadModel(String fs) CV_OVERRIDE;
bool setFaceDetector(FN_FaceDetector f, void* userdata) CV_OVERRIDE;
bool getFaces(InputArray image, OutputArray faces) CV_OVERRIDE;
bool fit(InputArray image, const std::vector<Rect>& faces, CV_OUT std::vector<std::vector<Point2f> >& landmarks ) CV_OVERRIDE;
bool fit(InputArray image, InputArray faces, OutputArrayOfArrays landmarks ) CV_OVERRIDE;
void training(String imageList, String groundTruth);
bool training(vector<Mat>& images, vector< vector<Point2f> >& landmarks,string filename,Size scale,string modelFilename) CV_OVERRIDE;
// Destructor for the class.

@ -103,11 +103,11 @@ public:
bool getData(void * items) CV_OVERRIDE;
bool fitConfig( InputArray image, const std::vector<Rect>& roi, std::vector<std::vector<Point2f> >& _landmarks, const std::vector<Config> &runtime_params ) CV_OVERRIDE;
bool fitConfig( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks, const std::vector<Config> &runtime_params ) CV_OVERRIDE;
protected:
bool fit( InputArray image, const std::vector<Rect>& faces, CV_OUT std::vector<std::vector<Point2f> >& landmarks ) CV_OVERRIDE;
bool fit( InputArray image, InputArray faces, OutputArrayOfArrays landmarks ) CV_OVERRIDE;
bool fitImpl( const Mat image, std::vector<Point2f>& landmarks,const Mat R,const Point2f T,const float scale, const int sclIdx=0 );
bool addTrainingSample(InputArray image, InputArray landmarks) CV_OVERRIDE;
@ -322,18 +322,54 @@ void FacemarkAAMImpl::training(void* parameters){
if(params.verbose) printf("Training is completed\n");
}
bool FacemarkAAMImpl::fit( InputArray image, const std::vector<Rect>& roi, CV_OUT std::vector<std::vector<Point2f> >& _landmarks )
/**
* @brief Copy the contents of a corners vector to an OutputArray, settings its size.
*/
static void _copyVector2Output(std::vector< std::vector< Point2f > > &vec, OutputArrayOfArrays out)
{
out.create((int)vec.size(), 1, CV_32FC2);
if (out.isMatVector()) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
Mat &m = out.getMatRef(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else if (out.isUMatVector()) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
UMat &m = out.getUMatRef(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else if (out.kind() == _OutputArray::STD_VECTOR_VECTOR) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
Mat m = out.getMat(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else {
CV_Error(cv::Error::StsNotImplemented,
"Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
}
}
bool FacemarkAAMImpl::fit( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks )
{
std::vector<Config> config; // empty
return fitConfig(image, roi, _landmarks, config);
}
bool FacemarkAAMImpl::fitConfig( InputArray image, const std::vector<Rect>& roi, std::vector<std::vector<Point2f> >& _landmarks, const std::vector<Config> &configs )
bool FacemarkAAMImpl::fitConfig( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks, const std::vector<Config> &configs )
{
const std::vector<Rect> & faces = roi;
Mat roimat = roi.getMat();
std::vector<Rect> faces = roimat.reshape(4, roimat.rows);
if(faces.size()<1) return false;
std::vector<std::vector<Point2f> > & landmarks = _landmarks;
std::vector<std::vector<Point2f> > landmarks;
landmarks.resize(faces.size());
Mat img = image.getMat();
@ -354,6 +390,7 @@ bool FacemarkAAMImpl::fitConfig( InputArray image, const std::vector<Rect>& roi,
fitImpl(img, landmarks[i], R,t, scale);
}
}
_copyVector2Output(landmarks, _landmarks);
return true;
}

@ -115,7 +115,7 @@ public:
protected:
bool fit( InputArray image, const std::vector<Rect> & faces, std::vector<std::vector<Point2f> > & landmarks ) CV_OVERRIDE;//!< from many ROIs
bool fit(InputArray image, InputArray faces, OutputArrayOfArrays landmarks) CV_OVERRIDE;
bool fitImpl( const Mat image, std::vector<Point2f> & landmarks );//!< from a face
bool addTrainingSample(InputArray image, InputArray landmarks) CV_OVERRIDE;
@ -370,12 +370,47 @@ void FacemarkLBFImpl::training(void* parameters){
isModelTrained = true;
}
bool FacemarkLBFImpl::fit( InputArray image, const std::vector<Rect> & roi, CV_OUT std::vector<std::vector<Point2f> > & _landmarks )
/**
* @brief Copy the contents of a corners vector to an OutputArray, settings its size.
*/
static void _copyVector2Output(std::vector< std::vector< Point2f > > &vec, OutputArrayOfArrays out)
{
const std::vector<Rect> & faces = roi;
out.create((int)vec.size(), 1, CV_32FC2);
if (out.isMatVector()) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
Mat &m = out.getMatRef(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else if (out.isUMatVector()) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
UMat &m = out.getUMatRef(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else if (out.kind() == _OutputArray::STD_VECTOR_VECTOR) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
Mat m = out.getMat(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else {
CV_Error(cv::Error::StsNotImplemented,
"Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
}
}
bool FacemarkLBFImpl::fit(InputArray image, InputArray roi, OutputArrayOfArrays _landmarks)
{
Mat roimat = roi.getMat();
std::vector<Rect> faces = roimat.reshape(4, roimat.rows);
if (faces.empty()) return false;
std::vector<std::vector<Point2f> > & landmarks = _landmarks;
std::vector<std::vector<Point2f> > landmarks;
landmarks.resize(faces.size());
@ -383,7 +418,7 @@ bool FacemarkLBFImpl::fit( InputArray image, const std::vector<Rect> & roi, CV_O
params.detectROI = faces[i];
fitImpl(image.getMat(), landmarks[i]);
}
_copyVector2Output(landmarks, _landmarks);
return true;
}

@ -168,15 +168,53 @@ void FacemarkKazemiImpl :: loadModel(String filename){
f.close();
isModelLoaded = true;
}
bool FacemarkKazemiImpl::fit(InputArray img, const std::vector<Rect>& roi, CV_OUT std::vector<std::vector<Point2f> >& landmarks){
/**
* @brief Copy the contents of a corners vector to an OutputArray, settings its size.
*/
static void _copyVector2Output(std::vector< std::vector< Point2f > > &vec, OutputArrayOfArrays out)
{
out.create((int)vec.size(), 1, CV_32FC2);
if (out.isMatVector()) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
Mat &m = out.getMatRef(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else if (out.isUMatVector()) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
UMat &m = out.getUMatRef(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else if (out.kind() == _OutputArray::STD_VECTOR_VECTOR) {
for (unsigned int i = 0; i < vec.size(); i++) {
out.create(68, 1, CV_32FC2, i);
Mat m = out.getMat(i);
Mat(Mat(vec[i]).t()).copyTo(m);
}
}
else {
CV_Error(cv::Error::StsNotImplemented,
"Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
}
}
bool FacemarkKazemiImpl::fit(InputArray img, InputArray roi, OutputArrayOfArrays _landmarks)
{
if(!isModelLoaded){
String error_message = "No model loaded. Aborting....";
CV_Error(Error::StsBadArg, error_message);
return false;
}
Mat image = img.getMat();
const std::vector<Rect> & faces = roi;
std::vector<std::vector<Point2f> > & shapes = landmarks;
Mat roimat = roi.getMat();
std::vector<Rect> faces = roimat.reshape(4, roimat.rows);
std::vector<std::vector<Point2f> > shapes;
shapes.resize(faces.size());
if(image.empty()){
@ -243,6 +281,7 @@ bool FacemarkKazemiImpl::fit(InputArray img, const std::vector<Rect>& roi, CV_OU
shapes[e][j].y=float(D.at<double>(1,0));
}
}
_copyVector2Output(shapes, _landmarks);
return true;
}
}//cv

Loading…
Cancel
Save