Skip to content

Commit 2af2028

Browse files
committed
Update eos to latest master (v0.15.0) & update 4dface accordingly
We make a few unnecessary core::Image conversions, but overall, it seems to run at least as fast or even faster (which is expected) Added a few 'const's too.
1 parent 1e26340 commit 2af2028

File tree

4 files changed

+40
-59
lines changed

4 files changed

+40
-59
lines changed

CMakeLists.txt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
project(4dface)
2-
cmake_minimum_required(VERSION 2.8.10)
2+
cmake_minimum_required(VERSION 2.8.12)
33
set(4dface_VERSION_MAJOR 0)
4-
set(4dface_VERSION_MINOR 2)
4+
set(4dface_VERSION_MINOR 3)
55
set(4dface_VERSION_PATCH 0)
66
set(4dface_VERSION ${4dface_VERSION_MAJOR}.${4dface_VERSION_MINOR}.${4dface_VERSION_PATCH})
77

@@ -43,7 +43,7 @@ set(CPACK_PACKAGE_VERSION_PATCH "${4dface_VERSION_PATCH}")
4343
include(CPack)
4444

4545
# Find dependencies:
46-
find_package(OpenCV 2.4.3 REQUIRED core imgproc highgui objdetect) # in 3.0: require videoio? Plus the thing Michael fixed for eos?
46+
find_package(OpenCV 3 REQUIRED core imgcodecs imgproc highgui videoio objdetect)
4747
message(STATUS "OpenCV include dir found at ${OpenCV_INCLUDE_DIRS}")
4848
message(STATUS "OpenCV library dir found at ${OpenCV_LIB_DIR}")
4949
set_target_properties(${OpenCV_LIBS} PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE)
@@ -82,10 +82,11 @@ set(superviseddescent_DIR "${CMAKE_SOURCE_DIR}/external/superviseddescent")
8282

8383
set(eos_INCLUDE_DIR "${eos_DIR}/include")
8484
set(superviseddescent_INCLUDE_DIR "${superviseddescent_DIR}/include")
85-
set(cereal_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/eos/3rdparty/cereal-1.1.1/include")
85+
set(cereal_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/eos/3rdparty/cereal/include")
8686
set(glm_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/eos/3rdparty/glm")
8787
set(nanoflann_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/eos/3rdparty/nanoflann/include")
8888
set(eigen3_nnls_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/eos/3rdparty/eigen3-nnls/src")
89+
set(toml11_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/eos/3rdparty/toml11")
8990

9091
# The new model is not in the repository, download it manually for now:
9192
if(NOT EXISTS "face_landmarks_model_rcr_68.bin")
@@ -110,15 +111,16 @@ include_directories(${cereal_INCLUDE_DIR})
110111
include_directories(${glm_INCLUDE_DIR})
111112
include_directories(${nanoflann_INCLUDE_DIR})
112113
include_directories(${eigen3_nnls_INCLUDE_DIR})
114+
include_directories(${toml11_INCLUDE_DIR})
113115

114116
add_executable(4dface apps/4dface.cpp apps/helpers.hpp)
115117
target_link_libraries(4dface ${OpenCV_LIBS} ${Boost_LIBRARIES})
116118

117119
# install targets:
118120
install(TARGETS 4dface DESTINATION bin)
119121
install(FILES ${eos_DIR}/share/sfm_shape_3448.bin DESTINATION share)
120-
install(FILES ${eos_DIR}/share/ibug2did.txt DESTINATION share)
121-
install(FILES ${eos_DIR}/share/model_contours.json DESTINATION share)
122+
install(FILES ${eos_DIR}/share/ibug_to_sfm.txt DESTINATION share)
123+
install(FILES ${eos_DIR}/share/sfm_model_contours.json DESTINATION share)
122124
install(FILES ${eos_DIR}/share/sfm_3448_edge_topology.json DESTINATION share)
123125
install(FILES ${eos_DIR}/share/expression_blendshapes_3448.bin DESTINATION share)
124126
install(FILES ${CMAKE_BINARY_DIR}/face_landmarks_model_rcr_68.bin DESTINATION share)

apps/4dface.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@
2121

2222
#include "eos/core/Landmark.hpp"
2323
#include "eos/core/LandmarkMapper.hpp"
24+
#include "eos/core/Mesh.hpp"
2425
#include "eos/fitting/fitting.hpp"
25-
#include "eos/fitting/orthographic_camera_estimation_linear.hpp"
2626
#include "eos/fitting/contour_correspondence.hpp"
2727
#include "eos/fitting/closest_edge_fitting.hpp"
2828
#include "eos/fitting/RenderingParameters.hpp"
2929
#include "eos/render/utils.hpp"
3030
#include "eos/render/render.hpp"
3131
#include "eos/render/texture_extraction.hpp"
32+
#include "eos/render/draw_utils.hpp"
33+
#include "eos/core/Image_opencv_interop.hpp"
3234

3335
#include "rcr/model.hpp"
3436
#include "cereal/cereal.hpp"
@@ -82,9 +84,9 @@ int main(int argc, char *argv[])
8284
"full path to OpenCV's face detector (haarcascade_frontalface_alt2.xml)")
8385
("landmarkdetector,l", po::value<fs::path>(&landmarkdetector)->required()->default_value("../share/face_landmarks_model_rcr_68.bin"),
8486
"learned landmark detection model")
85-
("mapping,p", po::value<fs::path>(&mappingsfile)->required()->default_value("../share/ibug2did.txt"),
87+
("mapping,p", po::value<fs::path>(&mappingsfile)->required()->default_value("../share/ibug_to_sfm.txt"),
8688
"landmark identifier to model vertex number mapping")
87-
("model-contour,c", po::value<fs::path>(&contourfile)->required()->default_value("../share/model_contours.json"),
89+
("model-contour,c", po::value<fs::path>(&contourfile)->required()->default_value("../share/sfm_model_contours.json"),
8890
"file with model contour indices")
8991
("edge-topology,e", po::value<fs::path>(&edgetopologyfile)->required()->default_value("../share/sfm_3448_edge_topology.json"),
9092
"file with model's precomputed edge topology")
@@ -109,11 +111,11 @@ int main(int argc, char *argv[])
109111
}
110112

111113
// Load the Morphable Model and the LandmarkMapper:
112-
morphablemodel::MorphableModel morphable_model = morphablemodel::load_model(modelfile.string());
113-
core::LandmarkMapper landmark_mapper = mappingsfile.empty() ? core::LandmarkMapper() : core::LandmarkMapper(mappingsfile);
114+
const morphablemodel::MorphableModel morphable_model = morphablemodel::load_model(modelfile.string());
115+
const core::LandmarkMapper landmark_mapper = mappingsfile.empty() ? core::LandmarkMapper() : core::LandmarkMapper(mappingsfile.string());
114116

115-
fitting::ModelContour model_contour = contourfile.empty() ? fitting::ModelContour() : fitting::ModelContour::load(contourfile.string());
116-
fitting::ContourLandmarks ibug_contour = fitting::ContourLandmarks::load(mappingsfile.string());
117+
const fitting::ModelContour model_contour = contourfile.empty() ? fitting::ModelContour() : fitting::ModelContour::load(contourfile.string());
118+
const fitting::ContourLandmarks ibug_contour = fitting::ContourLandmarks::load(mappingsfile.string());
117119

118120
rcr::detection_model rcr_model;
119121
// Load the landmark detection model:
@@ -145,9 +147,9 @@ int main(int argc, char *argv[])
145147
return EXIT_FAILURE;
146148
}
147149

148-
vector<morphablemodel::Blendshape> blendshapes = morphablemodel::load_blendshapes(blendshapesfile.string());
150+
const morphablemodel::Blendshapes blendshapes = morphablemodel::load_blendshapes(blendshapesfile.string());
149151

150-
morphablemodel::EdgeTopology edge_topology = morphablemodel::load_edge_topology(edgetopologyfile.string());
152+
const morphablemodel::EdgeTopology edge_topology = morphablemodel::load_edge_topology(edgetopologyfile.string());
151153

152154
cv::namedWindow("video", 1);
153155
cv::namedWindow("render", 1);
@@ -206,34 +208,37 @@ int main(int argc, char *argv[])
206208
// Fit the 3DMM:
207209
fitting::RenderingParameters rendering_params;
208210
vector<float> shape_coefficients, blendshape_coefficients;
209-
vector<Vec2f> image_points;
210-
render::Mesh mesh;
211-
std::tie(mesh, rendering_params) = fitting::fit_shape_and_pose(morphable_model, blendshapes, rcr_to_eos_landmark_collection(current_landmarks), landmark_mapper, unmodified_frame.cols, unmodified_frame.rows, edge_topology, ibug_contour, model_contour, 3, 5, 15.0f, boost::none, shape_coefficients, blendshape_coefficients, image_points);
211+
vector<Eigen::Vector2f> image_points;
212+
core::Mesh mesh;
213+
std::tie(mesh, rendering_params) = fitting::fit_shape_and_pose(morphable_model, blendshapes, rcr_to_eos_landmark_collection(current_landmarks), landmark_mapper, unmodified_frame.cols, unmodified_frame.rows, edge_topology, ibug_contour, model_contour, 3, 5, 15.0f, cpp17::nullopt, shape_coefficients, blendshape_coefficients, image_points);
212214

213215
// Draw the 3D pose of the face:
214216
draw_axes_topright(glm::eulerAngles(rendering_params.get_rotation())[0], glm::eulerAngles(rendering_params.get_rotation())[1], glm::eulerAngles(rendering_params.get_rotation())[2], frame);
215217

216218
// Wireframe rendering of mesh of this frame (non-averaged):
217-
draw_wireframe(frame, mesh, rendering_params.get_modelview(), rendering_params.get_projection(), fitting::get_opencv_viewport(frame.cols, frame.rows));
219+
render::draw_wireframe(frame, mesh, rendering_params.get_modelview(), rendering_params.get_projection(), fitting::get_opencv_viewport(frame.cols, frame.rows));
218220

219221
// Extract the texture using the fitted mesh from this frame:
220-
Mat affine_cam = fitting::get_3x4_affine_camera_matrix(rendering_params, frame.cols, frame.rows);
221-
Mat isomap = render::extract_texture(mesh, affine_cam, unmodified_frame, true, render::TextureInterpolation::NearestNeighbour, 512);
222+
const Eigen::Matrix<float, 3, 4> affine_cam = fitting::get_3x4_affine_camera_matrix(rendering_params, frame.cols, frame.rows);
223+
const Mat isomap = core::to_mat(render::extract_texture(mesh, affine_cam, core::from_mat(unmodified_frame), true, render::TextureInterpolation::NearestNeighbour, 512));
222224

223225
// Merge the isomaps - add the current one to the already merged ones:
224-
Mat merged_isomap = isomap_averaging.add_and_merge(isomap);
226+
const Mat merged_isomap = isomap_averaging.add_and_merge(isomap);
225227
// Same for the shape:
226228
shape_coefficients = pca_shape_merging.add_and_merge(shape_coefficients);
227-
auto merged_shape = morphable_model.get_shape_model().draw_sample(shape_coefficients) + morphablemodel::to_matrix(blendshapes) * Mat(blendshape_coefficients);
228-
render::Mesh merged_mesh = morphablemodel::sample_to_mesh(merged_shape, morphable_model.get_color_model().get_mean(), morphable_model.get_shape_model().get_triangle_list(), morphable_model.get_color_model().get_triangle_list(), morphable_model.get_texture_coordinates());
229+
const Eigen::VectorXf merged_shape =
230+
morphable_model.get_shape_model().draw_sample(shape_coefficients) +
231+
to_matrix(blendshapes) *
232+
Eigen::Map<const Eigen::VectorXf>(blendshape_coefficients.data(), blendshape_coefficients.size());
233+
const core::Mesh merged_mesh = morphablemodel::sample_to_mesh(merged_shape, morphable_model.get_color_model().get_mean(), morphable_model.get_shape_model().get_triangle_list(), morphable_model.get_color_model().get_triangle_list(), morphable_model.get_texture_coordinates());
229234

230235
// Render the model in a separate window using the estimated pose, shape and merged texture:
231-
Mat rendering;
236+
core::Image4u rendering;
232237
auto modelview_no_translation = rendering_params.get_modelview();
233238
modelview_no_translation[3][0] = 0;
234239
modelview_no_translation[3][1] = 0;
235240
std::tie(rendering, std::ignore) = render::render(merged_mesh, modelview_no_translation, glm::ortho(-130.0f, 130.0f, -130.0f, 130.0f), 256, 256, render::create_mipmapped_texture(merged_isomap), true, false, false);
236-
cv::imshow("render", rendering);
241+
cv::imshow("render", core::to_mat(rendering));
237242

238243
cv::imshow("video", frame);
239244
auto key = cv::waitKey(30);
@@ -244,8 +249,8 @@ int main(int argc, char *argv[])
244249
}
245250
if (key == 's') {
246251
// save an obj + current merged isomap to the disk:
247-
render::Mesh neutral_expression = morphablemodel::sample_to_mesh(morphable_model.get_shape_model().draw_sample(shape_coefficients), morphable_model.get_color_model().get_mean(), morphable_model.get_shape_model().get_triangle_list(), morphable_model.get_color_model().get_triangle_list(), morphable_model.get_texture_coordinates());
248-
render::write_textured_obj(neutral_expression, "current_merged.obj");
252+
const core::Mesh neutral_expression = morphablemodel::sample_to_mesh(morphable_model.get_shape_model().draw_sample(shape_coefficients), morphable_model.get_color_model().get_mean(), morphable_model.get_shape_model().get_triangle_list(), morphable_model.get_color_model().get_triangle_list(), morphable_model.get_texture_coordinates());
253+
core::write_textured_obj(neutral_expression, "current_merged.obj");
249254
cv::imwrite("current_merged.isomap.png", merged_isomap);
250255
}
251256
}

apps/helpers.hpp

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include "glm/mat4x4.hpp"
3333
#include "glm/gtc/matrix_transform.hpp"
3434

35+
#include "Eigen/Core"
36+
3537
#include "opencv2/core/core.hpp"
3638

3739
#include <vector>
@@ -75,8 +77,8 @@ cv::Rect rescale_facebox(cv::Rect facebox, float scaling, float translation_y)
7577
*/
7678
auto rcr_to_eos_landmark_collection(const rcr::LandmarkCollection<cv::Vec2f>& landmark_collection)
7779
{
78-
eos::core::LandmarkCollection<cv::Vec2f> eos_landmark_collection;
79-
std::transform(begin(landmark_collection), end(landmark_collection), std::back_inserter(eos_landmark_collection), [](auto&& lm) { return eos::core::Landmark<cv::Vec2f>{ lm.name, lm.coordinates }; });
80+
eos::core::LandmarkCollection<Eigen::Vector2f> eos_landmark_collection;
81+
std::transform(begin(landmark_collection), end(landmark_collection), std::back_inserter(eos_landmark_collection), [](auto&& lm) { return eos::core::Landmark<Eigen::Vector2f>{ lm.name, { lm.coordinates[0], lm.coordinates[1] } }; });
8082
return eos_landmark_collection;
8183
};
8284

@@ -113,34 +115,6 @@ cv::Rect make_bbox_square(cv::Rect bounding_box)
113115
return cv::Rect(center_x - box_size / 2.0, center_y - box_size / 2.0, box_size, box_size);
114116
};
115117

116-
/**
117-
* Draws the given mesh as wireframe into the image.
118-
*
119-
* It does backface culling, i.e. draws only vertices in CCW order.
120-
*
121-
* @param[in] image An image to draw into.
122-
* @param[in] mesh The mesh to draw.
123-
* @param[in] modelview Model-view matrix to draw the mesh.
124-
* @param[in] projection Projection matrix to draw the mesh.
125-
* @param[in] viewport Viewport to draw the mesh.
126-
* @param[in] colour Colour of the mesh to be drawn.
127-
*/
128-
void draw_wireframe(cv::Mat image, const eos::render::Mesh& mesh, glm::mat4x4 modelview, glm::mat4x4 projection, glm::vec4 viewport, cv::Scalar colour = cv::Scalar(0, 255, 0, 255))
129-
{
130-
for (const auto& triangle : mesh.tvi)
131-
{
132-
const auto p1 = glm::project({ mesh.vertices[triangle[0]][0], mesh.vertices[triangle[0]][1], mesh.vertices[triangle[0]][2] }, modelview, projection, viewport);
133-
const auto p2 = glm::project({ mesh.vertices[triangle[1]][0], mesh.vertices[triangle[1]][1], mesh.vertices[triangle[1]][2] }, modelview, projection, viewport);
134-
const auto p3 = glm::project({ mesh.vertices[triangle[2]][0], mesh.vertices[triangle[2]][1], mesh.vertices[triangle[2]][2] }, modelview, projection, viewport);
135-
if (eos::render::detail::are_vertices_ccw_in_screen_space(glm::vec2(p1), glm::vec2(p2), glm::vec2(p3)))
136-
{
137-
cv::line(image, cv::Point(p1.x, p1.y), cv::Point(p2.x, p2.y), colour);
138-
cv::line(image, cv::Point(p2.x, p2.y), cv::Point(p3.x, p3.y), colour);
139-
cv::line(image, cv::Point(p3.x, p3.y), cv::Point(p1.x, p1.y), colour);
140-
}
141-
}
142-
};
143-
144118
/**
145119
* @brief Merges isomaps from a live video with a weighted averaging, based
146120
* on the view angle of each vertex to the camera.

external/eos

Submodule eos updated 176 files

0 commit comments

Comments
 (0)