Commit 5f406bb4 authored by Patrik Huber's avatar Patrik Huber

Fixed MorphableModel sample and mesh functions when working with a shape-only model

parent 7e31b1d7
...@@ -139,18 +139,20 @@ public: ...@@ -139,18 +139,20 @@ public:
/** /**
* Returns a sample from the model with the given shape- and * Returns a sample from the model with the given shape- and
* color PCA coefficients. * colour PCA coefficients.
* *
* If one of the given vectors is empty, the mean is used. * If one of the given vectors is empty, the mean is used.
* The coefficient vectors should contain normalised, i.e. standard normal distributed coefficients. * The coefficient vectors should contain normalised, i.e. standard normal distributed coefficients.
* If the Morphable Model is a shape-only model (without colour model), make sure to
* leave \c color_coefficients empty.
* *
* @param[in] shape_coefficients The PCA coefficients used to generate the shape sample. * @param[in] shape_coefficients The PCA coefficients used to generate the shape sample.
* @param[in] color_coefficients The PCA coefficients used to generate the shape sample. * @param[in] color_coefficients The PCA coefficients used to generate the vertex colouring.
* @return A model instance with given coefficients. * @return A model instance with given coefficients.
*/ */
render::Mesh draw_sample(std::vector<float> shape_coefficients, std::vector<float> color_coefficients) render::Mesh draw_sample(std::vector<float> shape_coefficients, std::vector<float> color_coefficients)
{ {
assert(shape_model.get_data_dimension() == color_model.get_data_dimension()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models. assert(shape_model.get_data_dimension() == color_model.get_data_dimension() || !has_color_model()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models, or, alternatively, it has to be a shape-only model.
cv::Mat shape_sample; cv::Mat shape_sample;
cv::Mat color_sample; cv::Mat color_sample;
...@@ -178,6 +180,19 @@ public: ...@@ -178,6 +180,19 @@ public:
return mesh; return mesh;
}; };
/**
* Returns true if this Morphable Model contains a colour
* model. Returns false if it is a shape-only model.
*
* @return True if the Morphable Model has a colour model (i.e. is not a shape-only model).
*/
bool has_color_model() const
{
return !color_model.get_mean().empty();
};
std::vector<cv::Vec2f> gtc() const { return texture_coordinates; };
private: private:
PcaModel shape_model; ///< A PCA model of the shape PcaModel shape_model; ///< A PCA model of the shape
PcaModel color_model; ///< A PCA model of vertex color information PcaModel color_model; ///< A PCA model of vertex color information
...@@ -240,10 +255,12 @@ void save_model(MorphableModel model, std::string filename) ...@@ -240,10 +255,12 @@ void save_model(MorphableModel model, std::string filename)
namespace detail { /* eos::morphablemodel::detail */ namespace detail { /* eos::morphablemodel::detail */
/** /**
* Internal helper function that creates a Mesh from given shape and color * Internal helper function that creates a Mesh from given shape and colour
* PCA instances. Needs the vertex index lists as well to assemble the mesh - * PCA instances. Needs the vertex index lists as well to assemble the mesh -
* and optional texture coordinates. * and optional texture coordinates.
* *
* If \c color is empty, it will create a mesh without vertex colouring.
*
* @param[in] shape PCA shape model instance. * @param[in] shape PCA shape model instance.
* @param[in] color PCA color model instance. * @param[in] color PCA color model instance.
* @param[in] tvi Triangle vertex indices. * @param[in] tvi Triangle vertex indices.
...@@ -253,19 +270,25 @@ void save_model(MorphableModel model, std::string filename) ...@@ -253,19 +270,25 @@ void save_model(MorphableModel model, std::string filename)
*/ */
eos::render::Mesh sample_to_mesh(cv::Mat shape, cv::Mat color, std::vector<std::array<int, 3>> tvi, std::vector<std::array<int, 3>> tci, std::vector<cv::Vec2f> texture_coordinates /* = std::vector<cv::Vec2f>() */) eos::render::Mesh sample_to_mesh(cv::Mat shape, cv::Mat color, std::vector<std::array<int, 3>> tvi, std::vector<std::array<int, 3>> tci, std::vector<cv::Vec2f> texture_coordinates /* = std::vector<cv::Vec2f>() */)
{ {
assert(shape.rows == color.rows); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models. assert(shape.rows == color.rows || color.empty()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models, or, alternatively, it has to be a shape-only model.
auto num_vertices = shape.rows / 3; auto num_vertices = shape.rows / 3;
eos::render::Mesh mesh; eos::render::Mesh mesh;
// Construct the mesh vertices and vertex color information: // Construct the mesh vertices:
mesh.vertices.resize(num_vertices); mesh.vertices.resize(num_vertices);
mesh.colors.resize(num_vertices);
for (auto i = 0; i < num_vertices; ++i) { for (auto i = 0; i < num_vertices; ++i) {
mesh.vertices[i] = cv::Vec4f(shape.at<float>(i * 3 + 0), shape.at<float>(i * 3 + 1), shape.at<float>(i * 3 + 2), 1.0f); mesh.vertices[i] = cv::Vec4f(shape.at<float>(i * 3 + 0), shape.at<float>(i * 3 + 1), shape.at<float>(i * 3 + 2), 1.0f);
}
// Assign the vertex color information if it's not a shape-only model:
if (!color.empty()) {
mesh.colors.resize(num_vertices);
for (auto i = 0; i < num_vertices; ++i) {
mesh.colors[i] = cv::Vec3f(color.at<float>(i * 3 + 0), color.at<float>(i * 3 + 1), color.at<float>(i * 3 + 2)); // order in hdf5: RGB. Order in OCV: BGR. But order in vertex.color: RGB mesh.colors[i] = cv::Vec3f(color.at<float>(i * 3 + 0), color.at<float>(i * 3 + 1), color.at<float>(i * 3 + 2)); // order in hdf5: RGB. Order in OCV: BGR. But order in vertex.color: RGB
} }
}
// Assign the triangle lists: // Assign the triangle lists:
mesh.tvi = tvi; mesh.tvi = tvi;
......
...@@ -62,13 +62,20 @@ struct Mesh ...@@ -62,13 +62,20 @@ struct Mesh
*/ */
inline void write_obj(Mesh mesh, std::string filename) inline void write_obj(Mesh mesh, std::string filename)
{ {
assert(mesh.vertices.size() == mesh.colors.size()); assert(mesh.vertices.size() == mesh.colors.size() || mesh.colors.empty());
std::ofstream obj_file(filename); std::ofstream obj_file(filename);
if (mesh.colors.empty()) {
for (std::size_t i = 0; i < mesh.vertices.size(); ++i) {
obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " " << mesh.vertices[i][2] << " " << std::endl;
}
}
else {
for (std::size_t i = 0; i < mesh.vertices.size(); ++i) { for (std::size_t i = 0; i < mesh.vertices.size(); ++i) {
obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " " << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " " << mesh.colors[i][2] << " " << std::endl; obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " " << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " " << mesh.colors[i][2] << " " << std::endl;
} }
}
for (auto&& v : mesh.tvi) { for (auto&& v : mesh.tvi) {
// Add one because obj starts counting triangle indices at 1 // Add one because obj starts counting triangle indices at 1
...@@ -87,7 +94,7 @@ inline void write_obj(Mesh mesh, std::string filename) ...@@ -87,7 +94,7 @@ inline void write_obj(Mesh mesh, std::string filename)
*/ */
inline void write_textured_obj(Mesh mesh, std::string filename) inline void write_textured_obj(Mesh mesh, std::string filename)
{ {
assert(mesh.vertices.size() == mesh.colors.size() && !mesh.texcoords.empty()); assert((mesh.vertices.size() == mesh.colors.size() || mesh.colors.empty()) && !mesh.texcoords.empty());
std::ofstream obj_file(filename); std::ofstream obj_file(filename);
...@@ -96,9 +103,18 @@ inline void write_textured_obj(Mesh mesh, std::string filename) ...@@ -96,9 +103,18 @@ inline void write_textured_obj(Mesh mesh, std::string filename)
obj_file << "mtllib " << mtl_filename.string() << std::endl; // first line of the obj file obj_file << "mtllib " << mtl_filename.string() << std::endl; // first line of the obj file
for (std::size_t i = 0; i < mesh.vertices.size(); ++i) { // same as in write_obj() // same as in write_obj():
if (mesh.colors.empty()) {
for (std::size_t i = 0; i < mesh.vertices.size(); ++i) {
obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " " << mesh.vertices[i][2] << " " << std::endl;
}
}
else {
for (std::size_t i = 0; i < mesh.vertices.size(); ++i) {
obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " " << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " " << mesh.colors[i][2] << " " << std::endl; obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " " << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " " << mesh.colors[i][2] << " " << std::endl;
} }
}
// end
for (std::size_t i = 0; i < mesh.texcoords.size(); ++i) { for (std::size_t i = 0; i < mesh.texcoords.size(); ++i) {
obj_file << "vt " << mesh.texcoords[i][0] << " " << 1.0f - mesh.texcoords[i][1] << std::endl; obj_file << "vt " << mesh.texcoords[i][0] << " " << 1.0f - mesh.texcoords[i][1] << std::endl;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment