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()
# Source and header files:
set(SOURCES
src/eos/core/LandmarkMapper.cpp
src/eos/morphablemodel/MorphableModel.cpp
src/eos/morphablemodel/io/cvssp.cpp
src/eos/render/utils.cpp
)
......
......@@ -27,6 +27,14 @@
#include "eos/render/Mesh.hpp"
#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 morphablemodel {
......@@ -50,7 +58,9 @@ public:
* @param[in] colorModel A PCA model over the color (albedo).
* @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.
......@@ -58,21 +68,42 @@ public:
*
* @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.
*/
PcaModel getColorModel() const;
PcaModel getColorModel() const
{
return colorModel;
};
/**
* Returns the mean of the shape- and color model as a Mesh.
*
* @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
......@@ -83,7 +114,22 @@ public:
* @param[in] colorSigma The color model standard deviation.
* @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
......@@ -96,7 +142,35 @@ public:
* @param[in] colorCoefficients The PCA coefficients used to generate the shape sample.
* @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:
PcaModel shapeModel; ///< A PCA model of the shape
......@@ -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 eos */
......
......@@ -33,7 +33,7 @@ namespace eos {
namespace morphablemodel {
/**
* Forward declarations
* Forward declarations of free functions
*/
cv::Mat normalisePcaBasis(cv::Mat unnormalisedBasis, cv::Mat eigenvalues);
cv::Mat unnormalisePcaBasis(cv::Mat normalisedBasis, cv::Mat eigenvalues);
......@@ -64,7 +64,7 @@ public:
* @param[in] eigenvalues The eigenvalues used to build the PCA model.
* @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()();
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