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:
/**
* 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.
* 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] 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.
*/
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 color_sample;
......@@ -178,6 +180,19 @@ public:
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:
PcaModel shape_model; ///< A PCA model of the shape
PcaModel color_model; ///< A PCA model of vertex color information
......@@ -240,10 +255,12 @@ void save_model(MorphableModel model, std::string filename)
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 -
* 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] color PCA color model instance.
* @param[in] tvi Triangle vertex indices.
......@@ -253,18 +270,24 @@ 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>() */)
{
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;
eos::render::Mesh mesh;
// Construct the mesh vertices and vertex color information:
// Construct the mesh vertices:
mesh.vertices.resize(num_vertices);
mesh.colors.resize(num_vertices);
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.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 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
}
}
// Assign the triangle lists:
......
......@@ -62,12 +62,19 @@ struct Mesh
*/
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);
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;
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;
}
}
for (auto&& v : mesh.tvi) {
......@@ -87,7 +94,7 @@ inline void write_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);
......@@ -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
for (std::size_t i = 0; i < mesh.vertices.size(); ++i) { // same as in write_obj()
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;
// 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;
}
}
// end
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;
......
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