Skip to content

Commit 1faf7fd

Browse files
committed
Added wireframe output, cleaned up helpers file
1 parent f4a53a0 commit 1faf7fd

File tree

2 files changed

+28
-54
lines changed

2 files changed

+28
-54
lines changed

apps/4dface.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ int main(int argc, char *argv[])
190190
Rect ibug_facebox = rescale_facebox(detected_faces[0], 0.85, 0.2);
191191

192192
current_landmarks = rcr_model.detect(unmodified_frame, ibug_facebox);
193-
rcr::draw_landmarks(frame, current_landmarks);
193+
rcr::draw_landmarks(frame, current_landmarks, { 0, 0, 255 }); // red, initial landmarks
194194

195195
have_face = true;
196196
}
@@ -200,7 +200,7 @@ int main(int argc, char *argv[])
200200
auto enclosing_bbox = get_enclosing_bbox(rcr::to_row(current_landmarks));
201201
enclosing_bbox = make_bbox_square(enclosing_bbox);
202202
current_landmarks = rcr_model.detect(unmodified_frame, enclosing_bbox);
203-
rcr::draw_landmarks(frame, current_landmarks, { 0, 255, 0 }); // green, the new optimised landmarks
203+
rcr::draw_landmarks(frame, current_landmarks, { 255, 0, 0 }); // blue, the new optimised landmarks
204204
}
205205

206206
// Fit the 3DMM:
@@ -224,6 +224,9 @@ int main(int argc, char *argv[])
224224
auto merged_shape = morphable_model.get_shape_model().draw_sample(shape_coefficients) + morphablemodel::to_matrix(blendshapes) * Mat(blendshape_coefficients);
225225
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());
226226

227+
// Wireframe rendering of mesh of this frame (non-averaged):
228+
draw_wireframe(frame, mesh, rendering_params.get_modelview(), rendering_params.get_projection(), fitting::get_opencv_viewport(frame.cols, frame.rows));
229+
227230
// Render the model in a separate window using the estimated pose, shape and merged texture:
228231
Mat rendering;
229232
auto modelview_no_translation = rendering_params.get_modelview();

apps/helpers.hpp

Lines changed: 23 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@
2626
#include "eos/core/LandmarkMapper.hpp"
2727
#include "eos/morphablemodel/MorphableModel.hpp"
2828
#include "eos/morphablemodel/Blendshape.hpp"
29+
#include "eos/render/detail/render_detail.hpp"
2930
#include "rcr/landmark.hpp"
3031

32+
#include "glm/mat4x4.hpp"
33+
#include "glm/gtc/matrix_transform.hpp"
34+
3135
#include "opencv2/core/core.hpp"
3236

3337
#include <vector>
@@ -110,64 +114,31 @@ cv::Rect make_bbox_square(cv::Rect bounding_box)
110114
};
111115

112116
/**
113-
* @brief Takes LandmarkCollection of 2D landmarks and, using the landmark_mapper, find the
114-
* corresponding 3D vertex indices and returns them, along with the coordinates of the 3D point.
117+
* Draws the given mesh as wireframe into the image.
115118
*
116-
* The function only returns points which the landmark mapper was able to convert, and skips all
117-
* points for which there is no mapping. Thus, the number of returned points might be smaller than
118-
* the number of input points.
119-
* All three output vectors have the same size and contain the points in the same order.
120-
* landmarks can be an eos::core::LandmarkCollection<cv::Vec2f> or an rcr::LandmarkCollection<cv::Vec2f>.
119+
* It does backface culling, i.e. draws only vertices in CCW order.
121120
*
122-
* @param[in] landmarks A LandmarkCollection of 2D landmarks.
123-
* @param[in] landmark_mapper A mapper which maps the 2D landmark identifiers to 3D model vertex indices.
124-
* @param[in] morphable_model Model to get the 3D point coordinates from.
125-
* @return A tuple of <image_points, model_points, vertex_indices>.
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.
126127
*/
127-
template<class T>
128-
auto get_corresponding_pointset(const T& landmarks, const eos::core::LandmarkMapper& landmark_mapper, const eos::morphablemodel::MorphableModel& morphable_model)
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))
129129
{
130-
using cv::Mat;
131-
using std::vector;
132-
using cv::Vec2f;
133-
using cv::Vec4f;
134-
135-
// These will be the final 2D and 3D points used for the fitting:
136-
vector<Vec4f> model_points; // the points in the 3D shape model
137-
vector<int> vertex_indices; // their vertex indices
138-
vector<Vec2f> image_points; // the corresponding 2D landmark points
139-
140-
// Sub-select all the landmarks which we have a mapping for (i.e. that are defined in the 3DMM):
141-
for (int i = 0; i < landmarks.size(); ++i) {
142-
auto converted_name = landmark_mapper.convert(landmarks[i].name);
143-
if (!converted_name) { // no mapping defined for the current landmark
144-
continue;
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);
145140
}
146-
int vertex_idx = std::stoi(converted_name.get());
147-
Vec4f vertex = morphable_model.get_shape_model().get_mean_at_point(vertex_idx);
148-
model_points.emplace_back(vertex);
149-
vertex_indices.emplace_back(vertex_idx);
150-
image_points.emplace_back(landmarks[i].coordinates);
151141
}
152-
return std::make_tuple(image_points, model_points, vertex_indices);
153-
};
154-
155-
/**
156-
* @brief Concatenates two std::vector's of the same type and returns the concatenated
157-
* vector. The elements of the second vector are appended after the first one.
158-
*
159-
* @param[in] vec_a First vector.
160-
* @param[in] vec_b Second vector.
161-
* @return The concatenated vector.
162-
*/
163-
template <class T>
164-
auto concat(const std::vector<T>& vec_a, const std::vector<T>& vec_b)
165-
{
166-
std::vector<T> concatenated_vec;
167-
concatenated_vec.reserve(vec_a.size() + vec_b.size());
168-
concatenated_vec.insert(std::end(concatenated_vec), std::begin(vec_a), std::end(vec_a));
169-
concatenated_vec.insert(std::end(concatenated_vec), std::begin(vec_b), std::end(vec_b));
170-
return concatenated_vec;
171142
};
172143

173144
/**

0 commit comments

Comments
 (0)