Skip to content

Commit 84c882d

Browse files
committed
Merge pull request #2154 from LaurentBerger:py_face_landmark
2 parents fc979a8 + 4593e63 commit 84c882d

File tree

7 files changed

+158
-18
lines changed

7 files changed

+158
-18
lines changed

modules/face/include/opencv2/face/facemark.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ class CV_EXPORTS_W Facemark : public virtual Algorithm
7474
@endcode
7575
*/
7676
CV_WRAP virtual bool fit( InputArray image,
77-
const std::vector<Rect>& faces,
78-
CV_OUT std::vector<std::vector<Point2f> >& landmarks ) = 0;
77+
InputArray faces,
78+
OutputArrayOfArrays landmarks) = 0;
7979
}; /* Facemark*/
8080

8181

modules/face/include/opencv2/face/facemarkAAM.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class CV_EXPORTS_W FacemarkAAM : public FacemarkTrain
146146
};
147147

148148
//! overload with additional Config structures
149-
virtual bool fitConfig( InputArray image, const std::vector<Rect>& roi, std::vector<std::vector<Point2f> >& _landmarks, const std::vector<Config> &runtime_params ) = 0;
149+
virtual bool fitConfig( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks, const std::vector<Config> &runtime_params ) = 0;
150150

151151

152152
//! initializer
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import random
2+
import numpy as np
3+
import cv2 as cv
4+
5+
frame1 = cv.imread(cv.samples.findFile('lena.jpg'))
6+
if frame1 is None:
7+
print("image not found")
8+
exit()
9+
frame = np.vstack((frame1,frame1))
10+
facemark = cv.face.createFacemarkLBF()
11+
try:
12+
facemark.loadModel(cv.samples.findFile('lbfmodel.yaml'))
13+
except cv.error:
14+
print("Model not found\nlbfmodel.yaml can be download at")
15+
print("https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml")
16+
cascade = cv.CascadeClassifier(cv.samples.findFile('lbpcascade_frontalface_improved.xml'))
17+
if cascade.empty() :
18+
print("cascade not found")
19+
exit()
20+
faces = cascade.detectMultiScale(frame, 1.05, 3, cv.CASCADE_SCALE_IMAGE, (30, 30))
21+
ok, landmarks = facemark.fit(frame, faces=faces)
22+
cv.imshow("Image", frame)
23+
for marks in landmarks:
24+
couleur = (random.randint(0,255),
25+
random.randint(0,255),
26+
random.randint(0,255))
27+
cv.face.drawFacemarks(frame, marks, couleur)
28+
cv.imshow("Image Landmarks", frame)
29+
cv.waitKey()

modules/face/src/face_alignmentimpl.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class FacemarkKazemiImpl : public FacemarkKazemi{
7373
void loadModel(String fs) CV_OVERRIDE;
7474
bool setFaceDetector(FN_FaceDetector f, void* userdata) CV_OVERRIDE;
7575
bool getFaces(InputArray image, OutputArray faces) CV_OVERRIDE;
76-
bool fit(InputArray image, const std::vector<Rect>& faces, CV_OUT std::vector<std::vector<Point2f> >& landmarks ) CV_OVERRIDE;
76+
bool fit(InputArray image, InputArray faces, OutputArrayOfArrays landmarks ) CV_OVERRIDE;
7777
void training(String imageList, String groundTruth);
7878
bool training(vector<Mat>& images, vector< vector<Point2f> >& landmarks,string filename,Size scale,string modelFilename) CV_OVERRIDE;
7979
// Destructor for the class.

modules/face/src/facemarkAAM.cpp

+43-6
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ class FacemarkAAMImpl : public FacemarkAAM {
103103

104104
bool getData(void * items) CV_OVERRIDE;
105105

106-
bool fitConfig( InputArray image, const std::vector<Rect>& roi, std::vector<std::vector<Point2f> >& _landmarks, const std::vector<Config> &runtime_params ) CV_OVERRIDE;
106+
bool fitConfig( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks, const std::vector<Config> &runtime_params ) CV_OVERRIDE;
107107

108108
protected:
109109

110-
bool fit( InputArray image, const std::vector<Rect>& faces, CV_OUT std::vector<std::vector<Point2f> >& landmarks ) CV_OVERRIDE;
110+
bool fit( InputArray image, InputArray faces, OutputArrayOfArrays landmarks ) CV_OVERRIDE;
111111
bool fitImpl( const Mat image, std::vector<Point2f>& landmarks,const Mat R,const Point2f T,const float scale, const int sclIdx=0 );
112112

113113
bool addTrainingSample(InputArray image, InputArray landmarks) CV_OVERRIDE;
@@ -322,18 +322,54 @@ void FacemarkAAMImpl::training(void* parameters){
322322
if(params.verbose) printf("Training is completed\n");
323323
}
324324

325-
bool FacemarkAAMImpl::fit( InputArray image, const std::vector<Rect>& roi, CV_OUT std::vector<std::vector<Point2f> >& _landmarks )
325+
/**
326+
* @brief Copy the contents of a corners vector to an OutputArray, settings its size.
327+
*/
328+
static void _copyVector2Output(std::vector< std::vector< Point2f > > &vec, OutputArrayOfArrays out)
329+
{
330+
out.create((int)vec.size(), 1, CV_32FC2);
331+
332+
if (out.isMatVector()) {
333+
for (unsigned int i = 0; i < vec.size(); i++) {
334+
out.create(68, 1, CV_32FC2, i);
335+
Mat &m = out.getMatRef(i);
336+
Mat(Mat(vec[i]).t()).copyTo(m);
337+
}
338+
}
339+
else if (out.isUMatVector()) {
340+
for (unsigned int i = 0; i < vec.size(); i++) {
341+
out.create(68, 1, CV_32FC2, i);
342+
UMat &m = out.getUMatRef(i);
343+
Mat(Mat(vec[i]).t()).copyTo(m);
344+
}
345+
}
346+
else if (out.kind() == _OutputArray::STD_VECTOR_VECTOR) {
347+
for (unsigned int i = 0; i < vec.size(); i++) {
348+
out.create(68, 1, CV_32FC2, i);
349+
Mat m = out.getMat(i);
350+
Mat(Mat(vec[i]).t()).copyTo(m);
351+
}
352+
}
353+
else {
354+
CV_Error(cv::Error::StsNotImplemented,
355+
"Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
356+
}
357+
}
358+
359+
360+
bool FacemarkAAMImpl::fit( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks )
326361
{
327362
std::vector<Config> config; // empty
328363
return fitConfig(image, roi, _landmarks, config);
329364
}
330365

331-
bool FacemarkAAMImpl::fitConfig( InputArray image, const std::vector<Rect>& roi, std::vector<std::vector<Point2f> >& _landmarks, const std::vector<Config> &configs )
366+
bool FacemarkAAMImpl::fitConfig( InputArray image, InputArray roi, OutputArrayOfArrays _landmarks, const std::vector<Config> &configs )
332367
{
333-
const std::vector<Rect> & faces = roi;
368+
Mat roimat = roi.getMat();
369+
std::vector<Rect> faces = roimat.reshape(4, roimat.rows);
334370
if(faces.size()<1) return false;
335371

336-
std::vector<std::vector<Point2f> > & landmarks = _landmarks;
372+
std::vector<std::vector<Point2f> > landmarks;
337373
landmarks.resize(faces.size());
338374

339375
Mat img = image.getMat();
@@ -354,6 +390,7 @@ bool FacemarkAAMImpl::fitConfig( InputArray image, const std::vector<Rect>& roi,
354390
fitImpl(img, landmarks[i], R,t, scale);
355391
}
356392
}
393+
_copyVector2Output(landmarks, _landmarks);
357394

358395
return true;
359396
}

modules/face/src/facemarkLBF.cpp

+40-5
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class FacemarkLBFImpl : public FacemarkLBF {
115115

116116
protected:
117117

118-
bool fit( InputArray image, const std::vector<Rect> & faces, std::vector<std::vector<Point2f> > & landmarks ) CV_OVERRIDE;//!< from many ROIs
118+
bool fit(InputArray image, InputArray faces, OutputArrayOfArrays landmarks) CV_OVERRIDE;
119119
bool fitImpl( const Mat image, std::vector<Point2f> & landmarks );//!< from a face
120120

121121
bool addTrainingSample(InputArray image, InputArray landmarks) CV_OVERRIDE;
@@ -370,20 +370,55 @@ void FacemarkLBFImpl::training(void* parameters){
370370
isModelTrained = true;
371371
}
372372

373-
bool FacemarkLBFImpl::fit( InputArray image, const std::vector<Rect> & roi, CV_OUT std::vector<std::vector<Point2f> > & _landmarks )
373+
/**
374+
* @brief Copy the contents of a corners vector to an OutputArray, settings its size.
375+
*/
376+
static void _copyVector2Output(std::vector< std::vector< Point2f > > &vec, OutputArrayOfArrays out)
374377
{
375-
const std::vector<Rect> & faces = roi;
378+
out.create((int)vec.size(), 1, CV_32FC2);
379+
380+
if (out.isMatVector()) {
381+
for (unsigned int i = 0; i < vec.size(); i++) {
382+
out.create(68, 1, CV_32FC2, i);
383+
Mat &m = out.getMatRef(i);
384+
Mat(Mat(vec[i]).t()).copyTo(m);
385+
}
386+
}
387+
else if (out.isUMatVector()) {
388+
for (unsigned int i = 0; i < vec.size(); i++) {
389+
out.create(68, 1, CV_32FC2, i);
390+
UMat &m = out.getUMatRef(i);
391+
Mat(Mat(vec[i]).t()).copyTo(m);
392+
}
393+
}
394+
else if (out.kind() == _OutputArray::STD_VECTOR_VECTOR) {
395+
for (unsigned int i = 0; i < vec.size(); i++) {
396+
out.create(68, 1, CV_32FC2, i);
397+
Mat m = out.getMat(i);
398+
Mat(Mat(vec[i]).t()).copyTo(m);
399+
}
400+
}
401+
else {
402+
CV_Error(cv::Error::StsNotImplemented,
403+
"Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
404+
}
405+
}
406+
407+
bool FacemarkLBFImpl::fit(InputArray image, InputArray roi, OutputArrayOfArrays _landmarks)
408+
{
409+
Mat roimat = roi.getMat();
410+
std::vector<Rect> faces = roimat.reshape(4, roimat.rows);
376411
if (faces.empty()) return false;
377412

378-
std::vector<std::vector<Point2f> > & landmarks = _landmarks;
413+
std::vector<std::vector<Point2f> > landmarks;
379414

380415
landmarks.resize(faces.size());
381416

382417
for(unsigned i=0; i<faces.size();i++){
383418
params.detectROI = faces[i];
384419
fitImpl(image.getMat(), landmarks[i]);
385420
}
386-
421+
_copyVector2Output(landmarks, _landmarks);
387422
return true;
388423
}
389424

modules/face/src/getlandmarks.cpp

+42-3
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,53 @@ void FacemarkKazemiImpl :: loadModel(String filename){
168168
f.close();
169169
isModelLoaded = true;
170170
}
171-
bool FacemarkKazemiImpl::fit(InputArray img, const std::vector<Rect>& roi, CV_OUT std::vector<std::vector<Point2f> >& landmarks){
171+
172+
/**
173+
* @brief Copy the contents of a corners vector to an OutputArray, settings its size.
174+
*/
175+
static void _copyVector2Output(std::vector< std::vector< Point2f > > &vec, OutputArrayOfArrays out)
176+
{
177+
out.create((int)vec.size(), 1, CV_32FC2);
178+
179+
if (out.isMatVector()) {
180+
for (unsigned int i = 0; i < vec.size(); i++) {
181+
out.create(68, 1, CV_32FC2, i);
182+
Mat &m = out.getMatRef(i);
183+
Mat(Mat(vec[i]).t()).copyTo(m);
184+
}
185+
}
186+
else if (out.isUMatVector()) {
187+
for (unsigned int i = 0; i < vec.size(); i++) {
188+
out.create(68, 1, CV_32FC2, i);
189+
UMat &m = out.getUMatRef(i);
190+
Mat(Mat(vec[i]).t()).copyTo(m);
191+
}
192+
}
193+
else if (out.kind() == _OutputArray::STD_VECTOR_VECTOR) {
194+
for (unsigned int i = 0; i < vec.size(); i++) {
195+
out.create(68, 1, CV_32FC2, i);
196+
Mat m = out.getMat(i);
197+
Mat(Mat(vec[i]).t()).copyTo(m);
198+
}
199+
}
200+
else {
201+
CV_Error(cv::Error::StsNotImplemented,
202+
"Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
203+
}
204+
}
205+
206+
207+
bool FacemarkKazemiImpl::fit(InputArray img, InputArray roi, OutputArrayOfArrays _landmarks)
208+
{
172209
if(!isModelLoaded){
173210
String error_message = "No model loaded. Aborting....";
174211
CV_Error(Error::StsBadArg, error_message);
175212
return false;
176213
}
177214
Mat image = img.getMat();
178-
const std::vector<Rect> & faces = roi;
179-
std::vector<std::vector<Point2f> > & shapes = landmarks;
215+
Mat roimat = roi.getMat();
216+
std::vector<Rect> faces = roimat.reshape(4, roimat.rows);
217+
std::vector<std::vector<Point2f> > shapes;
180218
shapes.resize(faces.size());
181219

182220
if(image.empty()){
@@ -243,6 +281,7 @@ bool FacemarkKazemiImpl::fit(InputArray img, const std::vector<Rect>& roi, CV_OU
243281
shapes[e][j].y=float(D.at<double>(1,0));
244282
}
245283
}
284+
_copyVector2Output(shapes, _landmarks);
246285
return true;
247286
}
248287
}//cv

0 commit comments

Comments
 (0)