Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
P
py-3d-face-reconstruction
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Richard Torenvliet
py-3d-face-reconstruction
Commits
d99c5f0e
Commit
d99c5f0e
authored
8 years ago
by
Richard Torenvliet
Browse files
Options
Downloads
Patches
Plain Diff
Use pybind11 instead of c headers
parent
292bf39b
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
Dockerfile
+6
-0
6 additions, 0 deletions
Dockerfile
makefile
+21
-1
21 additions, 1 deletion
makefile
src/reconstruction/fit-model.cpp
+18
-177
18 additions, 177 deletions
src/reconstruction/fit-model.cpp
src/test/reconstruction_test.py
+2
-3
2 additions, 3 deletions
src/test/reconstruction_test.py
with
47 additions
and
181 deletions
Dockerfile
+
6
−
0
View file @
d99c5f0e
...
@@ -32,6 +32,12 @@ RUN cmake ../ \
...
@@ -32,6 +32,12 @@ RUN cmake ../ \
-DPYTHON_EXECUTABLE
=
/usr/bin/python
-DPYTHON_EXECUTABLE
=
/usr/bin/python
RUN
make
&&
make
install
RUN
make
&&
make
install
ENV
PYTHONPATH=/usr/local/eos/bin/:$PYTHONPATH
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
WORKDIR
/src
This diff is collapsed.
Click to expand it.
makefile
+
21
−
1
View file @
d99c5f0e
...
@@ -44,5 +44,25 @@ $(SITE_PACKAGES)/cv%:
...
@@ -44,5 +44,25 @@ $(SITE_PACKAGES)/cv%:
@
ls
$@
@
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
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 $@
)
\
)'
This diff is collapsed.
Click to expand it.
src/reconstruction/fit-model.cpp
+
18
−
177
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.
* eos - A 3D Morphable Model fitting library written in modern C++11/14.
*
*
* File: examples/fit-model.cpp
* File: examples/fit-model.cpp
*
*
* Copyright 2015 Patrik Huber *
* Copyright 2015 Patrik Huber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* You may obtain a copy of the License at
...
@@ -16,8 +26,6 @@
...
@@ -16,8 +26,6 @@
* See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and
* limitations under the License.
* limitations under the License.
*/
*/
#include
<Python.h>
#include
"eos/core/Landmark.hpp"
#include
"eos/core/Landmark.hpp"
#include
"eos/core/LandmarkMapper.hpp"
#include
"eos/core/LandmarkMapper.hpp"
#include
"eos/fitting/orthographic_camera_estimation_linear.hpp"
#include
"eos/fitting/orthographic_camera_estimation_linear.hpp"
...
@@ -41,7 +49,6 @@ namespace po = boost::program_options;
...
@@ -41,7 +49,6 @@ namespace po = boost::program_options;
namespace
fs
=
boost
::
filesystem
;
namespace
fs
=
boost
::
filesystem
;
using
eos
::
core
::
Landmark
;
using
eos
::
core
::
Landmark
;
using
eos
::
core
::
LandmarkCollection
;
using
eos
::
core
::
LandmarkCollection
;
using
eos
::
core
::
LandmarkMapper
;
using
cv
::
Mat
;
using
cv
::
Mat
;
using
cv
::
Vec2f
;
using
cv
::
Vec2f
;
using
cv
::
Vec3f
;
using
cv
::
Vec3f
;
...
@@ -51,56 +58,6 @@ using std::endl;
...
@@ -51,56 +58,6 @@ using std::endl;
using
std
::
vector
;
using
std
::
vector
;
using
std
::
string
;
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
* 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)
...
@@ -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
* is estimated, and then, using this camera matrix, the shape is fitted
* to the landmarks.
* 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:
// Load the image, landmarks, LandmarkMapper and the Morphable Model:
Mat
image
=
cv
::
imread
(
imagefile
.
string
());
Mat
image
=
cv
::
imread
(
imagefile
.
string
());
LandmarkCollection
<
cv
::
Vec2f
>
landmarks
;
LandmarkCollection
<
cv
::
Vec2f
>
landmarks
;
...
@@ -156,7 +81,6 @@ int main(int argc, char *argv[])
...
@@ -156,7 +81,6 @@ int main(int argc, char *argv[])
return
EXIT_FAILURE
;
return
EXIT_FAILURE
;
}
}
morphablemodel
::
MorphableModel
morphable_model
;
morphablemodel
::
MorphableModel
morphable_model
;
try
{
try
{
morphable_model
=
morphablemodel
::
load_model
(
modelfile
.
string
());
morphable_model
=
morphablemodel
::
load_model
(
modelfile
.
string
());
}
}
...
@@ -164,19 +88,12 @@ int main(int argc, char *argv[])
...
@@ -164,19 +88,12 @@ int main(int argc, char *argv[])
cout
<<
"Error loading the Morphable Model: "
<<
e
.
what
()
<<
endl
;
cout
<<
"Error loading the Morphable Model: "
<<
e
.
what
()
<<
endl
;
return
EXIT_FAILURE
;
return
EXIT_FAILURE
;
}
}
core
::
LandmarkMapper
landmark_mapper
=
mappingsfile
.
empty
()
?
core
::
LandmarkMapper
()
:
core
::
LandmarkMapper
(
mappingsfile
);
core
::
LandmarkMapper
landmark_mapper
=
mappingsfile
.
empty
()
?
core
::
LandmarkMapper
()
:
core
::
LandmarkMapper
(
mappingsfile
);
// Draw the loaded landmarks:
// Draw the loaded landmarks:
Mat
outimg
=
image
.
clone
();
Mat
outimg
=
image
.
clone
();
for
(
auto
&&
lm
:
landmarks
)
{
for
(
auto
&&
lm
:
landmarks
)
{
cv
::
rectangle
(
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
});
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:
// These will be the final 2D and 3D points used for the fitting:
...
@@ -207,9 +124,7 @@ int main(int argc, char *argv[])
...
@@ -207,9 +124,7 @@ int main(int argc, char *argv[])
// Estimate the shape coefficients by fitting the shape to the landmarks:
// 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
);
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
(
vector
<
float
>
fitted_coeffs
=
fitting
::
fit_shape_to_landmarks_linear
(
morphable_model
,
affine_from_ortho
,
image_points
,
vertex_indices
);
morphable_model
,
affine_from_ortho
,
image_points
,
vertex_indices
);
// Obtain the full mesh with the estimated coefficients:
// Obtain the full mesh with the estimated coefficients:
render
::
Mesh
mesh
=
morphable_model
.
draw_sample
(
fitted_coeffs
,
vector
<
float
>
());
render
::
Mesh
mesh
=
morphable_model
.
draw_sample
(
fitted_coeffs
,
vector
<
float
>
());
...
@@ -230,84 +145,10 @@ int main(int argc, char *argv[])
...
@@ -230,84 +145,10 @@ int main(int argc, char *argv[])
return
EXIT_SUCCESS
;
return
EXIT_SUCCESS
;
}
}
static
PyObject
*
fit_model
(
PyObject
*
self
,
PyObject
*
args
)
{
PYBIND11_PLUGIN
(
fit
)
{
LandmarkCollection
<
cv
::
Vec2f
>
landmarks
;
py
::
module
m
(
"fit"
,
"fit example"
);
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
}
};
m
.
def
(
"add"
,
&
add
,
"A function which adds two numbers"
);
PyMODINIT_FUNC
initfit
(
void
)
{
return
m
.
ptr
();
(
void
)
Py_InitModule
(
"fit"
,
module_methods
);
}
}
This diff is collapsed.
Click to expand it.
src/test/reconstruction_test.py
+
2
−
3
View file @
d99c5f0e
...
@@ -49,8 +49,7 @@ def fit_model():
...
@@ -49,8 +49,7 @@ def fit_model():
input_points
=
dataset_module
.
factory
(
filename
=
image_filename
)
input_points
=
dataset_module
.
factory
(
filename
=
image_filename
)
input_image
=
input_points
.
get_image
()
input_image
=
input_points
.
get_image
()
fit
.
fit_model
(
image
)
print
(
fit
.
add
(
1
,
3
)
)
if
__name__
==
'
__main__
'
:
if
__name__
==
'
__main__
'
:
#fit_model()
fit_model
()
shape
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment