Commit 2b975f86 authored by Patrik Huber's avatar Patrik Huber

Moved MorphableModel functions to the header.

Fixed PcaModel c'tor, forgot to copy the arguments
parent 047d7252
...@@ -45,7 +45,6 @@ endif() ...@@ -45,7 +45,6 @@ endif()
# Source and header files: # Source and header files:
set(SOURCES set(SOURCES
src/eos/core/LandmarkMapper.cpp src/eos/core/LandmarkMapper.cpp
src/eos/morphablemodel/MorphableModel.cpp
src/eos/morphablemodel/io/cvssp.cpp src/eos/morphablemodel/io/cvssp.cpp
src/eos/render/utils.cpp src/eos/render/utils.cpp
) )
......
...@@ -27,6 +27,14 @@ ...@@ -27,6 +27,14 @@
#include "eos/render/Mesh.hpp" #include "eos/render/Mesh.hpp"
#include <vector> #include <vector>
#include <array>
/**
* Forward declaration of an internal function
*/
namespace eos { namespace morphablemodel { namespace detail {
eos::render::Mesh sampleToMesh(cv::Mat shape, cv::Mat color, std::vector<std::array<int, 3>> tvi, std::vector<std::array<int, 3>> tci, std::vector<cv::Vec2f> textureCoordinates = std::vector<cv::Vec2f>());
} } }
namespace eos { namespace eos {
namespace morphablemodel { namespace morphablemodel {
...@@ -50,7 +58,9 @@ public: ...@@ -50,7 +58,9 @@ public:
* @param[in] colorModel A PCA model over the color (albedo). * @param[in] colorModel A PCA model over the color (albedo).
* @param[in] textureCoordinates Optional texture coordinates for every vertex. * @param[in] textureCoordinates Optional texture coordinates for every vertex.
*/ */
MorphableModel(PcaModel shapeModel, PcaModel colorModel, std::vector<cv::Vec2f> textureCoordinates = std::vector<cv::Vec2f>()); MorphableModel(PcaModel shapeModel, PcaModel colorModel, std::vector<cv::Vec2f> textureCoordinates = std::vector<cv::Vec2f>()) : shapeModel(shapeModel), colorModel(colorModel), textureCoordinates(textureCoordinates)
{
};
/** /**
* Returns the PCA shape model of this Morphable Model. * Returns the PCA shape model of this Morphable Model.
...@@ -58,21 +68,42 @@ public: ...@@ -58,21 +68,42 @@ public:
* *
* @return The shape model. * @return The shape model.
*/ */
PcaModel getShapeModel() const; PcaModel getShapeModel() const
{
return shapeModel;
};
/** /**
* Returns the PCA color or albedo model of this Morphable Model. * Returns the PCA color (albedo) model of this Morphable Model.
* *
* @return The color model. * @return The color model.
*/ */
PcaModel getColorModel() const; PcaModel getColorModel() const
{
return colorModel;
};
/** /**
* Returns the mean of the shape- and color model as a Mesh. * Returns the mean of the shape- and color model as a Mesh.
* *
* @return An mesh instance of the mean of the Morphable Model. * @return An mesh instance of the mean of the Morphable Model.
*/ */
render::Mesh getMean() const; render::Mesh getMean() const
{
assert(shapeModel.getDataDimension() == colorModel.getDataDimension()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
cv::Mat shape = shapeModel.getMean();
cv::Mat color = colorModel.getMean();
render::Mesh mesh;
if (hasTextureCoordinates()) {
mesh = detail::sampleToMesh(shape, color, shapeModel.getTriangleList(), colorModel.getTriangleList(), textureCoordinates);
}
else {
mesh = detail::sampleToMesh(shape, color, shapeModel.getTriangleList(), colorModel.getTriangleList());
}
return mesh;
};
/** /**
* Draws a random sample from the model, where the coefficients * Draws a random sample from the model, where the coefficients
...@@ -83,7 +114,22 @@ public: ...@@ -83,7 +114,22 @@ public:
* @param[in] colorSigma The color model standard deviation. * @param[in] colorSigma The color model standard deviation.
* @return A random sample from the model. * @return A random sample from the model.
*/ */
render::Mesh drawSample(float shapeSigma = 1.0f, float colorSigma = 1.0f); render::Mesh drawSample(float shapeSigma = 1.0f, float colorSigma = 1.0f)
{
assert(shapeModel.getDataDimension() == colorModel.getDataDimension()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
cv::Mat shapeSample = shapeModel.drawSample(shapeSigma);
cv::Mat colorSample = colorModel.drawSample(colorSigma);
render::Mesh mesh;
if (hasTextureCoordinates()) {
mesh = detail::sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList(), textureCoordinates);
}
else {
mesh = detail::sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList());
}
return mesh;
};
/** /**
* Returns a sample from the model with the given shape- and * Returns a sample from the model with the given shape- and
...@@ -96,7 +142,35 @@ public: ...@@ -96,7 +142,35 @@ public:
* @param[in] colorCoefficients The PCA coefficients used to generate the shape sample. * @param[in] colorCoefficients The PCA coefficients used to generate the shape sample.
* @return A model instance with given coefficients. * @return A model instance with given coefficients.
*/ */
render::Mesh drawSample(std::vector<float> shapeCoefficients, std::vector<float> colorCoefficients); render::Mesh drawSample(std::vector<float> shapeCoefficients, std::vector<float> colorCoefficients)
{
assert(shapeModel.getDataDimension() == colorModel.getDataDimension()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
cv::Mat shapeSample;
cv::Mat colorSample;
if (shapeCoefficients.empty()) {
shapeSample = shapeModel.getMean();
}
else {
shapeSample = shapeModel.drawSample(shapeCoefficients);
}
if (colorCoefficients.empty()) {
colorSample = colorModel.getMean();
}
else {
colorSample = colorModel.drawSample(colorCoefficients);
}
render::Mesh mesh;
if (hasTextureCoordinates()) {
mesh = detail::sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList(), textureCoordinates);
}
else {
mesh = detail::sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList());
}
return mesh;
};
private: private:
PcaModel shapeModel; ///< A PCA model of the shape PcaModel shapeModel; ///< A PCA model of the shape
...@@ -115,6 +189,51 @@ private: ...@@ -115,6 +189,51 @@ private:
}; };
namespace detail { /* eos::morphablemodel::detail */
/**
* Internal helper function that creates a Mesh from given shape and color
* PCA instances. Needs the vertex index lists as well to assemble the mesh -
* and optional texture coordinates.
*
* @param[in] shape PCA shape model instance.
* @param[in] color PCA color model instance.
* @param[in] tvi Triangle vertex indices.
* @param[in] tci Triangle color indices (usually identical to the vertex indices).
* @param[in] textureCoordinates Optional texture coordinates for each vertex.
* @return A mesh created from given parameters.
*/
eos::render::Mesh sampleToMesh(cv::Mat shape, cv::Mat color, std::vector<std::array<int, 3>> tvi, std::vector<std::array<int, 3>> tci, std::vector<cv::Vec2f> textureCoordinates /* = std::vector<cv::Vec2f>() */)
{
assert(shape.rows == color.rows); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
auto numVertices = shape.rows / 3;
eos::render::Mesh mesh;
// Construct the mesh vertices and vertex color information:
mesh.vertices.resize(numVertices);
mesh.colors.resize(numVertices);
for (auto i = 0; i < numVertices; ++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 triangle lists:
mesh.tvi = tvi;
mesh.tci = tci;
// Texture coordinates, if the model has them:
if (!textureCoordinates.empty()) {
mesh.texcoords.resize(numVertices);
for (auto i = 0; i < numVertices; ++i) {
mesh.texcoords[i] = textureCoordinates[i];
}
}
return mesh;
};
} /* namespace detail */
} /* namespace morphablemodel */ } /* namespace morphablemodel */
} /* namespace eos */ } /* namespace eos */
......
...@@ -33,7 +33,7 @@ namespace eos { ...@@ -33,7 +33,7 @@ namespace eos {
namespace morphablemodel { namespace morphablemodel {
/** /**
* Forward declarations * Forward declarations of free functions
*/ */
cv::Mat normalisePcaBasis(cv::Mat unnormalisedBasis, cv::Mat eigenvalues); cv::Mat normalisePcaBasis(cv::Mat unnormalisedBasis, cv::Mat eigenvalues);
cv::Mat unnormalisePcaBasis(cv::Mat normalisedBasis, cv::Mat eigenvalues); cv::Mat unnormalisePcaBasis(cv::Mat normalisedBasis, cv::Mat eigenvalues);
...@@ -64,7 +64,7 @@ public: ...@@ -64,7 +64,7 @@ public:
* @param[in] eigenvalues The eigenvalues used to build the PCA model. * @param[in] eigenvalues The eigenvalues used to build the PCA model.
* @param[in] triangleList An index list of how to assemble the mesh. * @param[in] triangleList An index list of how to assemble the mesh.
*/ */
PcaModel(cv::Mat mean, cv::Mat pcaBasis, cv::Mat eigenvalues, std::vector<std::array<int, 3>> triangleList) PcaModel(cv::Mat mean, cv::Mat pcaBasis, cv::Mat eigenvalues, std::vector<std::array<int, 3>> triangleList) : mean(mean), normalisedPcaBasis(pcaBasis), eigenvalues(eigenvalues), triangleList(triangleList)
{ {
const auto seed = std::random_device()(); const auto seed = std::random_device()();
engine.seed(seed); engine.seed(seed);
......
/*
* Eos - A 3D Morphable Model fitting library written in modern C++11/14.
*
* File: include/eos/morphablemodel/MorphableModel.cpp
*
* Copyright 2014, 2015 Patrik Huber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "eos/morphablemodel/MorphableModel.hpp"
#include "opencv2/core/core.hpp"
#include <iostream>
using cv::Mat;
using cv::Vec2f;
using cv::Vec3f;
using cv::Vec4f;
using std::vector;
using std::array;
namespace {
/**
* Internal helper function that creates a Mesh from given shape and color
* PCA instances. Needs the vertex index lists as well to assemble the mesh -
* and optional texture coordinates.
*
* @param[in] shape PCA shape model instance.
* @param[in] color PCA color model instance.
* @param[in] tvi Triangle vertex indices.
* @param[in] tci Triangle color indices (usually identical to the vertex indices).
* @param[in] textureCoordinates Optional texture coordinates for each vertex.
* @return A mesh created from given parameters.
*/
eos::render::Mesh sampleToMesh(Mat shape, Mat color, vector<array<int, 3>> tvi, vector<array<int, 3>> tci, vector<Vec2f> textureCoordinates = vector<Vec2f>())
{
assert(shape.rows == color.rows); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
auto numVertices = shape.rows / 3;
eos::render::Mesh mesh;
// Construct the mesh vertices and vertex color information:
mesh.vertices.resize(numVertices);
mesh.colors.resize(numVertices);
for (auto i = 0; i < numVertices; ++i) {
mesh.vertices[i] = Vec4f(shape.at<float>(i * 3 + 0), shape.at<float>(i * 3 + 1), shape.at<float>(i * 3 + 2), 1.0f);
mesh.colors[i] = 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:
mesh.tvi = tvi;
mesh.tci = tci;
// Texture coordinates, if the model has them:
if (!textureCoordinates.empty()) {
mesh.texcoords.resize(numVertices);
for (auto i = 0; i < numVertices; ++i) {
mesh.texcoords[i] = textureCoordinates[i];
}
}
return mesh;
}
} /* unnamed namespace */
namespace eos {
namespace morphablemodel {
MorphableModel::MorphableModel(PcaModel shapeModel, PcaModel colorModel, std::vector<cv::Vec2f> textureCoordinates /*= std::vector<cv::Vec2f>()*/) : shapeModel(shapeModel), colorModel(colorModel), textureCoordinates(textureCoordinates)
{
}
PcaModel MorphableModel::getShapeModel() const
{
return shapeModel;
}
PcaModel MorphableModel::getColorModel() const
{
return colorModel;
}
render::Mesh MorphableModel::getMean() const
{
assert(shapeModel.getDataDimension() == colorModel.getDataDimension()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
Mat shape = shapeModel.getMean();
Mat color = colorModel.getMean();
render::Mesh mesh;
if (hasTextureCoordinates()) {
mesh = sampleToMesh(shape, color, shapeModel.getTriangleList(), colorModel.getTriangleList(), textureCoordinates);
}
else {
mesh = sampleToMesh(shape, color, shapeModel.getTriangleList(), colorModel.getTriangleList());
}
return mesh;
}
render::Mesh MorphableModel::drawSample(float shapeSigma /*= 1.0f*/, float colorSigma /*= 1.0f*/)
{
assert(shapeModel.getDataDimension() == colorModel.getDataDimension()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
Mat shapeSample = shapeModel.drawSample(shapeSigma);
Mat colorSample = colorModel.drawSample(colorSigma);
render::Mesh mesh;
if (hasTextureCoordinates()) {
mesh = sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList(), textureCoordinates);
}
else {
mesh = sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList());
}
return mesh;
}
render::Mesh MorphableModel::drawSample(vector<float> shapeCoefficients, vector<float> colorCoefficients)
{
assert(shapeModel.getDataDimension() == colorModel.getDataDimension()); // The number of vertices (= model.getDataDimension() / 3) has to be equal for both models.
Mat shapeSample;
Mat colorSample;
if (shapeCoefficients.empty()) {
shapeSample = shapeModel.getMean();
} else {
shapeSample = shapeModel.drawSample(shapeCoefficients);
}
if (colorCoefficients.empty()) {
colorSample = colorModel.getMean();
} else {
colorSample = colorModel.drawSample(colorCoefficients);
}
render::Mesh mesh;
if (hasTextureCoordinates()) {
mesh = sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList(), textureCoordinates);
}
else {
mesh = sampleToMesh(shapeSample, colorSample, shapeModel.getTriangleList(), colorModel.getTriangleList());
}
return mesh;
}
} /* namespace morphablemodel */
} /* namespace eos */
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