Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
py-3d-face-reconstruction
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Richard Torenvliet
py-3d-face-reconstruction
Commits
d99c5f0e
Commit
d99c5f0e
authored
Nov 24, 2016
by
Richard Torenvliet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use pybind11 instead of c headers
parent
292bf39b
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
47 additions
and
181 deletions
+47
-181
Dockerfile
Dockerfile
+6
-0
makefile
makefile
+21
-1
src/reconstruction/fit-model.cpp
src/reconstruction/fit-model.cpp
+18
-177
src/test/reconstruction_test.py
src/test/reconstruction_test.py
+2
-3
No files found.
Dockerfile
View file @
d99c5f0e
...
...
@@ -32,6 +32,12 @@ RUN cmake ../ \
-DPYTHON_EXECUTABLE
=
/usr/bin/python
RUN
make
&&
make
install
ENV
PYTHONPATH=/usr/local/eos/bin/:$PYTHONPATH
WORKDIR
/libs
RUN
git clone https://github.com/pybind/pybind11.git
RUN
(
cd
pybind11
;
mkdir
build
;
cd
build
;
cmake
-DPYBIND11_PYTHON_VERSION
=
2.7 ..
)
;
RUN
(
cd
pybind11/build
;
make
-j4
&&
make
install
)
;
WORKDIR
/src
makefile
View file @
d99c5f0e
...
...
@@ -44,5 +44,25 @@ $(SITE_PACKAGES)/cv%:
@
ls
$@
#src/reconstruction/fit.so: src/reconstruction/fit-model.cpp
# $(BASE_DOCKER_CMD) /bin/bash -c '(cd reconstruction; python setup.py build_ext --inplace)'
src/reconstruction/fit.so
:
src/reconstruction/fit-model.cpp
$(BASE_DOCKER_CMD)
/bin/bash
-c
'(cd reconstruction; python setup.py build_ext --inplace)'
$(BASE_DOCKER_CMD)
/bin/bash
-c
\
'(cd reconstruction; \
g++ -fPIC -O3 -shared -std=c++11 \
-I/usr/local/include/pybind11/include/ \
-I/usr/local/eos/include/ \
-I/usr/local/eos/3rdparty/glm/ \
-I/usr/local/eos/3rdparty/cereal-1.1.1/include/ \
-I/usr/local/include/opencv2/ \
-I/usr/include/boost/ \
-L/usr/local/eos/bin/ \
-L/usr/lib/x86_64-linux-gnu/ \
-L/usr/local/lib/ \
-lboost_program_options \
-lfile_system \
-lopencv_world \
`python-config --cflags --ldflags` \
$(
notdir
$^
)
-o
$(
notdir
$@
)
\
)'
src/reconstruction/fit-model.cpp
View file @
d99c5f0e
#include <pybind11/pybind11.h>
namespace
py
=
pybind11
;
int
add
(
int
i
,
int
j
)
{
return
i
+
j
;
}
/*
* eos - A 3D Morphable Model fitting library written in modern C++11/14.
*
* File: examples/fit-model.cpp
*
* Copyright 2015 Patrik Huber *
* Copyright 2015 Patrik Huber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
...
...
@@ -16,8 +26,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <Python.h>
#include "eos/core/Landmark.hpp"
#include "eos/core/LandmarkMapper.hpp"
#include "eos/fitting/orthographic_camera_estimation_linear.hpp"
...
...
@@ -41,7 +49,6 @@ namespace po = boost::program_options;
namespace
fs
=
boost
::
filesystem
;
using
eos
::
core
::
Landmark
;
using
eos
::
core
::
LandmarkCollection
;
using
eos
::
core
::
LandmarkMapper
;
using
cv
::
Mat
;
using
cv
::
Vec2f
;
using
cv
::
Vec3f
;
...
...
@@ -51,56 +58,6 @@ using std::endl;
using
std
::
vector
;
using
std
::
string
;
/**
* Reads an ibug .pts landmark file and returns an ordered vector with
* the 68 2D landmark coordinates.
*
* @param[in] filename Path to a .pts file.
* @return An ordered vector with the 68 ibug landmarks.
*/
LandmarkCollection
<
cv
::
Vec2f
>
read_pts_landmarks
(
std
::
string
filename
)
{
using
std
::
getline
;
using
cv
::
Vec2f
;
using
std
::
string
;
LandmarkCollection
<
Vec2f
>
landmarks
;
landmarks
.
reserve
(
68
);
std
::
ifstream
file
(
filename
);
if
(
!
file
.
is_open
())
{
throw
std
::
runtime_error
(
string
(
"Could not open landmark file: "
+
filename
));
}
string
line
;
// Skip the first 3 lines, they're header lines:
getline
(
file
,
line
);
// 'version: 1'
getline
(
file
,
line
);
// 'n_points : 68'
getline
(
file
,
line
);
// '{'
int
ibugId
=
1
;
while
(
getline
(
file
,
line
))
{
if
(
line
==
"}"
)
{
// end of the file
break
;
}
std
::
stringstream
lineStream
(
line
);
Landmark
<
Vec2f
>
landmark
;
landmark
.
name
=
std
::
to_string
(
ibugId
);
if
(
!
(
lineStream
>>
landmark
.
coordinates
[
0
]
>>
landmark
.
coordinates
[
1
]))
{
throw
std
::
runtime_error
(
string
(
"Landmark format error while parsing the line: "
+
line
));
}
// From the iBug website:
// "Please note that the re-annotated data for this challenge are saved in the Matlab convention of 1 being
// the first index, i.e. the coordinates of the top left pixel in an image are x=1, y=1."
// ==> So we shift every point by 1:
landmark
.
coordinates
[
0
]
-=
1.0
f
;
landmark
.
coordinates
[
1
]
-=
1.0
f
;
landmarks
.
emplace_back
(
landmark
);
++
ibugId
;
}
return
landmarks
;
};
/**
* This app demonstrates estimation of the camera and fitting of the shape
...
...
@@ -111,40 +68,8 @@ LandmarkCollection<cv::Vec2f> read_pts_landmarks(std::string filename)
* is estimated, and then, using this camera matrix, the shape is fitted
* to the landmarks.
*/
int
main
(
int
argc
,
char
*
argv
[])
int
fit
(
int
argc
,
char
*
argv
[])
{
fs
::
path
modelfile
,
isomapfile
,
imagefile
,
landmarksfile
,
mappingsfile
,
outputfile
;
try
{
po
::
options_description
desc
(
"Allowed options"
);
desc
.
add_options
()
(
"help,h"
,
"display the help message"
)
(
"model,m"
,
po
::
value
<
fs
::
path
>
(
&
modelfile
)
->
required
()
->
default_value
(
"../share/sfm_shape_3448.bin"
),
"a Morphable Model stored as cereal BinaryArchive"
)
(
"image,i"
,
po
::
value
<
fs
::
path
>
(
&
imagefile
)
->
required
()
->
default_value
(
"data/image_0010.png"
),
"an input image"
)
(
"landmarks,l"
,
po
::
value
<
fs
::
path
>
(
&
landmarksfile
)
->
required
()
->
default_value
(
"data/image_0010.pts"
),
"2D landmarks for the image, in ibug .pts format"
)
(
"mapping,p"
,
po
::
value
<
fs
::
path
>
(
&
mappingsfile
)
->
required
()
->
default_value
(
"../share/ibug2did.txt"
),
"landmark identifier to model vertex number mapping"
)
(
"output,o"
,
po
::
value
<
fs
::
path
>
(
&
outputfile
)
->
required
()
->
default_value
(
"out"
),
"basename for the output rendering and obj files"
)
;
po
::
variables_map
vm
;
po
::
store
(
po
::
command_line_parser
(
argc
,
argv
).
options
(
desc
).
run
(),
vm
);
if
(
vm
.
count
(
"help"
))
{
cout
<<
"Usage: fit-model [options]"
<<
endl
;
cout
<<
desc
;
return
EXIT_SUCCESS
;
}
po
::
notify
(
vm
);
}
catch
(
const
po
::
error
&
e
)
{
cout
<<
"Error while parsing command-line arguments: "
<<
e
.
what
()
<<
endl
;
cout
<<
"Use --help to display a list of options."
<<
endl
;
return
EXIT_SUCCESS
;
}
// Load the image, landmarks, LandmarkMapper and the Morphable Model:
Mat
image
=
cv
::
imread
(
imagefile
.
string
());
LandmarkCollection
<
cv
::
Vec2f
>
landmarks
;
...
...
@@ -156,7 +81,6 @@ int main(int argc, char *argv[])
return
EXIT_FAILURE
;
}
morphablemodel
::
MorphableModel
morphable_model
;
try
{
morphable_model
=
morphablemodel
::
load_model
(
modelfile
.
string
());
}
...
...
@@ -164,19 +88,12 @@ int main(int argc, char *argv[])
cout
<<
"Error loading the Morphable Model: "
<<
e
.
what
()
<<
endl
;
return
EXIT_FAILURE
;
}
core
::
LandmarkMapper
landmark_mapper
=
mappingsfile
.
empty
()
?
core
::
LandmarkMapper
()
:
core
::
LandmarkMapper
(
mappingsfile
);
// Draw the loaded landmarks:
Mat
outimg
=
image
.
clone
();
for
(
auto
&&
lm
:
landmarks
)
{
cv
::
rectangle
(
outimg
,
cv
::
Point2f
(
lm
.
coordinates
[
0
]
-
2.0
f
,
lm
.
coordinates
[
1
]
-
2.0
f
),
cv
::
Point2f
(
lm
.
coordinates
[
0
]
+
2.0
f
,
lm
.
coordinates
[
1
]
+
2.0
f
),
{
255
,
0
,
0
}
);
cv
::
rectangle
(
outimg
,
cv
::
Point2f
(
lm
.
coordinates
[
0
]
-
2.0
f
,
lm
.
coordinates
[
1
]
-
2.0
f
),
cv
::
Point2f
(
lm
.
coordinates
[
0
]
+
2.0
f
,
lm
.
coordinates
[
1
]
+
2.0
f
),
{
255
,
0
,
0
});
}
// These will be the final 2D and 3D points used for the fitting:
...
...
@@ -207,9 +124,7 @@ int main(int argc, char *argv[])
// Estimate the shape coefficients by fitting the shape to the landmarks:
Mat
affine_from_ortho
=
fitting
::
get_3x4_affine_camera_matrix
(
rendering_params
,
image
.
cols
,
image
.
rows
);
vector
<
float
>
fitted_coeffs
=
fitting
::
fit_shape_to_landmarks_linear
(
morphable_model
,
affine_from_ortho
,
image_points
,
vertex_indices
);
vector
<
float
>
fitted_coeffs
=
fitting
::
fit_shape_to_landmarks_linear
(
morphable_model
,
affine_from_ortho
,
image_points
,
vertex_indices
);
// Obtain the full mesh with the estimated coefficients:
render
::
Mesh
mesh
=
morphable_model
.
draw_sample
(
fitted_coeffs
,
vector
<
float
>
());
...
...
@@ -230,84 +145,10 @@ int main(int argc, char *argv[])
return
EXIT_SUCCESS
;
}
static
PyObject
*
fit_model
(
PyObject
*
self
,
PyObject
*
args
)
{
LandmarkCollection
<
cv
::
Vec2f
>
landmarks
;
morphablemodel
::
MorphableModel
morphable_model
;
LandmarkMapper
(
"/usr/local/eos/share/ibug2did.txt"
);
morphable_model
=
morphablemodel
::
load_model
(
"/usr/local/eos/share/sfm_shape_3448.bin"
);
// Draw the loaded landmarks:
//Mat outimg = image.clone();
//for (auto&& lm : landmarks) {
// cv::rectangle(
// outimg,
// cv::Point2f(lm.coordinates[0] - 2.0f, lm.coordinates[1] - 2.0f),
// cv::Point2f(lm.coordinates[0] + 2.0f, lm.coordinates[1] + 2.0f),
// { 255, 0, 0 }
// );
//}
//// These will be the final 2D and 3D points used for the fitting:
//vector<Vec4f> model_points; // the points in the 3D shape model
//vector<int> vertex_indices; // their vertex indices
//vector<Vec2f> image_points; // the corresponding 2D landmark points
//// Sub-select all the landmarks which we have a mapping for (i.e. that are defined in the 3DMM):
//for (int i = 0; i < landmarks.size(); ++i) {
// auto converted_name = landmark_mapper.convert(landmarks[i].name);
// if (!converted_name) { // no mapping defined for the current landmark
// continue;
// }
// int vertex_idx = std::stoi(converted_name.get());
// Vec4f vertex = morphable_model.get_shape_model().get_mean_at_point(vertex_idx);
// model_points.emplace_back(vertex);
// vertex_indices.emplace_back(vertex_idx);
// image_points.emplace_back(landmarks[i].coordinates);
//}
//// Estimate the camera (pose) from the 2D - 3D point correspondences
//fitting::ScaledOrthoProjectionParameters pose = fitting::estimate_orthographic_projection_linear(image_points, model_points, true, image.rows);
//fitting::RenderingParameters rendering_params(pose, image.cols, image.rows);
//// The 3D head pose can be recovered as follows:
//float yaw_angle = glm::degrees(glm::yaw(rendering_params.get_rotation()));
//// and similarly for pitch and roll.
//// Estimate the shape coefficients by fitting the shape to the landmarks:
//Mat affine_from_ortho = fitting::get_3x4_affine_camera_matrix(rendering_params, image.cols, image.rows);
//vector<float> fitted_coeffs = fitting::fit_shape_to_landmarks_linear(
// morphable_model, affine_from_ortho, image_points, vertex_indices
//);
//// Obtain the full mesh with the estimated coefficients:
//render::Mesh mesh = morphable_model.draw_sample(fitted_coeffs, vector<float>());
//// Extract the texture from the image using given mesh and camera parameters:
//Mat isomap = render::extract_texture(mesh, affine_from_ortho, image);
//// Save the mesh as textured obj:
//outputfile += fs::path(".obj");
//render::write_textured_obj(mesh, outputfile.string());
//// And save the isomap:
//outputfile.replace_extension(".isomap.png");
//cv::imwrite(outputfile.string(), isomap);
//cout << "Finished fitting and wrote result mesh and isomap to files with basename " << outputfile.stem().stem() << "." << endl;
//return EXIT_SUCCESS;
Py_RETURN_NONE
;
}
static
PyMethodDef
module_methods
[]
=
{
// name of function, function_name
{
"fit_model"
,
fit_model
,
METH_VARARGS
,
"Fits an image with given landmarks to a 3DMM"
},
{
NULL
,
NULL
,
0
,
NULL
}
};
PYBIND11_PLUGIN
(
fit
)
{
py
::
module
m
(
"fit"
,
"fit example"
);
m
.
def
(
"add"
,
&
add
,
"A function which adds two numbers"
);
PyMODINIT_FUNC
initfit
(
void
)
{
(
void
)
Py_InitModule
(
"fit"
,
module_methods
);
return
m
.
ptr
();
}
src/test/reconstruction_test.py
View file @
d99c5f0e
...
...
@@ -49,8 +49,7 @@ def fit_model():
input_points
=
dataset_module
.
factory
(
filename
=
image_filename
)
input_image
=
input_points
.
get_image
()
fit
.
fit_model
(
image
)
print
(
fit
.
add
(
1
,
3
)
)
if
__name__
==
'__main__'
:
#fit_model()
shape
()
fit_model
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment