eos  0.7.1
MorphableModel.hpp
1 /*
2  * Eos - A 3D Morphable Model fitting library written in modern C++11/14.
3  *
4  * File: include/eos/morphablemodel/MorphableModel.hpp
5  *
6  * Copyright 2014, 2015 Patrik Huber
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 #pragma once
21 
22 #ifndef MORPHABLEMODEL_HPP_
23 #define MORPHABLEMODEL_HPP_
24 
25 #include "eos/morphablemodel/PcaModel.hpp"
26 
27 #include "eos/render/Mesh.hpp"
28 
29 #include "eos/morphablemodel/io/mat_cerealisation.hpp"
30 #include "cereal/cereal.hpp"
31 #include "cereal/access.hpp"
32 #include "cereal/types/vector.hpp"
33 #include "cereal/archives/binary.hpp"
34 
35 #include <vector>
36 #include <array>
37 #include <cstdint>
38 
39 // Forward declaration of an internal function
40 namespace eos { namespace morphablemodel { namespace detail {
41  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>());
42 } } }
43 
44 namespace eos {
45  namespace morphablemodel {
46 
55 {
56 public:
57  MorphableModel() = default;
58 
67  MorphableModel(PcaModel shape_model, PcaModel color_model, std::vector<cv::Vec2f> texture_coordinates = std::vector<cv::Vec2f>()) : shape_model(shape_model), color_model(color_model), texture_coordinates(texture_coordinates)
68  {
69  };
70 
78  {
79  return shape_model;
80  };
81 
88  {
89  return color_model;
90  };
91 
98  {
99  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.
100 
101  cv::Mat shape = shape_model.get_mean();
102  cv::Mat color = color_model.get_mean();
103 
104  render::Mesh mesh;
105  if (has_texture_coordinates()) {
106  mesh = detail::sample_to_mesh(shape, color, shape_model.get_triangle_list(), color_model.get_triangle_list(), texture_coordinates);
107  }
108  else {
109  mesh = detail::sample_to_mesh(shape, color, shape_model.get_triangle_list(), color_model.get_triangle_list());
110  }
111  return mesh;
112  };
113 
123  render::Mesh draw_sample(float shape_sigma = 1.0f, float color_sigma = 1.0f)
124  {
125  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.
126 
127  cv::Mat shapeSample = shape_model.draw_sample(shape_sigma);
128  cv::Mat colorSample = color_model.draw_sample(color_sigma);
129 
130  render::Mesh mesh;
131  if (has_texture_coordinates()) {
132  mesh = detail::sample_to_mesh(shapeSample, colorSample, shape_model.get_triangle_list(), color_model.get_triangle_list(), texture_coordinates);
133  }
134  else {
135  mesh = detail::sample_to_mesh(shapeSample, colorSample, shape_model.get_triangle_list(), color_model.get_triangle_list());
136  }
137  return mesh;
138  };
139 
154  render::Mesh draw_sample(std::vector<float> shape_coefficients, std::vector<float> color_coefficients) const
155  {
156  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.
157 
158  cv::Mat shape_sample;
159  cv::Mat color_sample;
160 
161  if (shape_coefficients.empty()) {
162  shape_sample = shape_model.get_mean();
163  }
164  else {
165  shape_sample = shape_model.draw_sample(shape_coefficients);
166  }
167  if (color_coefficients.empty()) {
168  color_sample = color_model.get_mean();
169  }
170  else {
171  color_sample = color_model.draw_sample(color_coefficients);
172  }
173 
174  render::Mesh mesh;
175  if (has_texture_coordinates()) {
176  mesh = detail::sample_to_mesh(shape_sample, color_sample, shape_model.get_triangle_list(), color_model.get_triangle_list(), texture_coordinates);
177  }
178  else {
179  mesh = detail::sample_to_mesh(shape_sample, color_sample, shape_model.get_triangle_list(), color_model.get_triangle_list());
180  }
181  return mesh;
182  };
183 
190  bool has_color_model() const
191  {
192  return !color_model.get_mean().empty();
193  };
194 
200  std::vector<cv::Vec2f> get_texture_coordinates() const
201  {
202  return texture_coordinates;
203  };
204 
205 private:
206  PcaModel shape_model;
207  PcaModel color_model;
208  std::vector<cv::Vec2f> texture_coordinates;
209 
216  bool has_texture_coordinates() const {
217  return texture_coordinates.size() > 0 ? true : false;
218  };
219 
220  friend class cereal::access;
226  template<class Archive>
227  void serialize(Archive& archive, const std::uint32_t version)
228  {
229  archive(shape_model, color_model, texture_coordinates);
230  };
231 };
232 
241 MorphableModel load_model(std::string filename)
242 {
243  MorphableModel model;
244 
245  std::ifstream file(filename, std::ios::binary);
246  if (file.fail()) {
247  throw std::runtime_error("Error opening given file: " + filename);
248  }
249  cereal::BinaryInputArchive input_archive(file);
250  input_archive(model);
251 
252  return model;
253 };
254 
262 void save_model(MorphableModel model, std::string filename)
263 {
264  std::ofstream file(filename, std::ios::binary);
265  cereal::BinaryOutputArchive output_archive(file);
266  output_archive(model);
267 };
268 
269 
270 namespace detail { /* eos::morphablemodel::detail */
285 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>() */)
286 {
287  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.
288 
289  auto num_vertices = shape.rows / 3;
290 
291  eos::render::Mesh mesh;
292 
293  // Construct the mesh vertices:
294  mesh.vertices.resize(num_vertices);
295  for (auto i = 0; i < num_vertices; ++i) {
296  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);
297  }
298 
299  // Assign the vertex color information if it's not a shape-only model:
300  if (!color.empty()) {
301  mesh.colors.resize(num_vertices);
302  for (auto i = 0; i < num_vertices; ++i) {
303  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
304  }
305  }
306 
307  // Assign the triangle lists:
308  mesh.tvi = tvi;
309  mesh.tci = tci; // tci will be empty in case of a shape-only model
310 
311  // Texture coordinates, if the model has them:
312  if (!texture_coordinates.empty()) {
313  mesh.texcoords.resize(num_vertices);
314  for (auto i = 0; i < num_vertices; ++i) {
315  mesh.texcoords[i] = texture_coordinates[i];
316  }
317  }
318 
319  return mesh;
320 };
321 } /* namespace eos::morphablemodel::detail */
322 
323  } /* namespace morphablemodel */
324 } /* namespace eos */
325 
326 CEREAL_CLASS_VERSION(eos::morphablemodel::MorphableModel, 0);
327 
328 #endif /* MORPHABLEMODEL_HPP_ */
std::vector< std::array< int, 3 > > tci
Triangle color indices.
Definition: Mesh.hpp:52
This class represents a PCA-model that consists of:
Definition: PcaModel.hpp:55
PcaModel get_color_model() const
Definition: MorphableModel.hpp:87
render::Mesh get_mean() const
Definition: MorphableModel.hpp:97
cv::Mat draw_sample(float sigma=1.0f)
Definition: PcaModel.hpp:143
void save_model(MorphableModel model, std::string filename)
Definition: MorphableModel.hpp:262
int get_data_dimension() const
Definition: PcaModel.hpp:98
std::vector< std::array< int, 3 > > get_triangle_list() const
Definition: PcaModel.hpp:109
std::vector< cv::Vec2f > get_texture_coordinates() const
Definition: MorphableModel.hpp:200
Namespace containing all of eos&#39;s 3D model fitting functionality.
MorphableModel load_model(std::string filename)
Definition: MorphableModel.hpp:241
std::vector< cv::Vec4f > vertices
3D vertex positions.
Definition: Mesh.hpp:47
std::vector< cv::Vec3f > colors
Colour information for each vertex. Expected to be in RGB order.
Definition: Mesh.hpp:48
bool has_color_model() const
Definition: MorphableModel.hpp:190
cv::Mat get_mean() const
Definition: PcaModel.hpp:119
This class represents a 3D mesh consisting of vertices, vertex colour information and texture coordin...
Definition: Mesh.hpp:45
MorphableModel(PcaModel shape_model, PcaModel color_model, std::vector< cv::Vec2f > texture_coordinates=std::vector< cv::Vec2f >())
Definition: MorphableModel.hpp:67
PcaModel get_shape_model() const
Definition: MorphableModel.hpp:77
std::vector< std::array< int, 3 > > tvi
Triangle vertex indices.
Definition: Mesh.hpp:51
std::vector< cv::Vec2f > texcoords
Texture coordinates for each vertex.
Definition: Mesh.hpp:49
render::Mesh draw_sample(std::vector< float > shape_coefficients, std::vector< float > color_coefficients) const
Definition: MorphableModel.hpp:154
render::Mesh draw_sample(float shape_sigma=1.0f, float color_sigma=1.0f)
Definition: MorphableModel.hpp:123
A class representing a 3D Morphable Model, consisting of a shape- and colour (albedo) PCA model...
Definition: MorphableModel.hpp:54