Commit 97fa8725 authored by Patrik Huber's avatar Patrik Huber

Changed OrthographicRenderingParameters to RenderingParameters and added a camera type

I don't think we need two representations for it, one struct with a type is easier. At the moment, we only use an orthographic camera anyway.

- As before, it should contain all the parameters necessary to render an image using OpenGL, and conform to the OpenGL conventions
- Updated all calling sites
- Added serialisation
- Added a convenience method to save the parameters to a json file
parent 248fd9a9
...@@ -187,7 +187,7 @@ int main(int argc, char *argv[]) ...@@ -187,7 +187,7 @@ int main(int argc, char *argv[])
} }
// Estimate the camera (pose) from the 2D - 3D point correspondences // Estimate the camera (pose) from the 2D - 3D point correspondences
fitting::OrthographicRenderingParameters rendering_params = fitting::estimate_orthographic_camera(image_points, model_points, image.cols, image.rows); fitting::RenderingParameters rendering_params = fitting::estimate_orthographic_camera(image_points, model_points, image.cols, image.rows);
Mat affine_from_ortho = get_3x4_affine_camera_matrix(rendering_params, image.cols, image.rows); Mat affine_from_ortho = get_3x4_affine_camera_matrix(rendering_params, image.cols, image.rows);
// The 3D head pose can be recovered as follows: // The 3D head pose can be recovered as follows:
......
/*! \file boost_optional.hpp
\brief Support for boost::optional
\ingroup OtherTypes */
/*
Copyright (c) 2014, Steve Hickman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL STEVE HICKMAN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_TYPES_BOOST_OPTIONAL_HPP_
#define CEREAL_TYPES_BOOST_OPTIONAL_HPP_
#include <cereal/cereal.hpp>
#include <boost/optional.hpp>
namespace cereal
{
//! Saving for boost::optional
template <class Archive, class Optioned> inline
void save(Archive & ar, ::boost::optional<Optioned> const & optional)
{
bool initFlag = (bool)optional;
if (initFlag)
{
ar(make_nvp("initialized", true));
ar(make_nvp("value", optional.get()));
}
else
{
ar(make_nvp("initialized", false));
}
}
//! Loading for boost::optional
template <class Archive, class Optioned> inline
void load(Archive & ar, ::boost::optional<Optioned> & optional)
{
bool initFlag;
ar(make_nvp("initialized", initFlag));
if (initFlag)
{
Optioned val;
ar(make_nvp("value", val));
optional = val;
}
else
optional = ::boost::none; // this is all we need to do to reset the internal flag and value
}
} // namespace cereal
#endif // CEREAL_TYPES_BOOST_OPTIONAL_HPP_
...@@ -26,11 +26,17 @@ ...@@ -26,11 +26,17 @@
#include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/matrix_transform.hpp"
#include "eos/fitting/detail/optional_cerealisation.hpp"
#include "cereal/cereal.hpp"
#include "cereal/archives/json.hpp"
#include "Eigen/Geometry" #include "Eigen/Geometry"
#include "unsupported/Eigen/NonLinearOptimization" #include "unsupported/Eigen/NonLinearOptimization"
#include "opencv2/core/core.hpp" #include "opencv2/core/core.hpp"
#include "boost/optional.hpp"
#include <vector> #include <vector>
#include <cassert> #include <cassert>
...@@ -45,6 +51,26 @@ struct Frustum ...@@ -45,6 +51,26 @@ struct Frustum
{ {
float l, r, b, t; float l, r, b, t;
// optional<float> n, f; // optional<float> n, f;
boost::optional<float> n;
boost::optional<float> f;
friend class cereal::access;
/**
* Serialises this class using cereal.
*
* @param[in] ar The archive to serialise to (or to serialise from).
*/
template<class Archive>
void serialize(Archive& archive)
{
archive(CEREAL_NVP(l), CEREAL_NVP(r), CEREAL_NVP(b), CEREAL_NVP(t), CEREAL_NVP(n), CEREAL_NVP(f));
};
};
enum class CameraType
{
Orthographic,
Perspective
}; };
/** /**
...@@ -64,14 +90,50 @@ struct Frustum ...@@ -64,14 +90,50 @@ struct Frustum
* The rotation values are given in radians and estimated using the RPY convention. * The rotation values are given in radians and estimated using the RPY convention.
* Yaw is applied first to the model, then pitch, then roll (R * P * Y * vertex). * Yaw is applied first to the model, then pitch, then roll (R * P * Y * vertex).
*/ */
struct OrthographicRenderingParameters struct RenderingParameters
{ {
CameraType camera_type; // what's the default?
Frustum frustum;
float r_x; // Pitch. float r_x; // Pitch.
float r_y; // Yaw. Positive means subject is looking left (we see her right cheek). float r_y; // Yaw. Positive means subject is looking left (we see her right cheek).
float r_z; // Roll. Positive means the subject's right eye is further down than the other one (he tilts his head to the right). float r_z; // Roll. Positive means the subject's right eye is further down than the other one (he tilts his head to the right).
float t_x; float t_x; // Todo: define whether it's the camera translation/rotation or the model's.
float t_y; float t_y;
Frustum frustum;
int screen_width;
int screen_height;
boost::optional<float> focal_length; // only for certain camera types
friend class cereal::access;
/**
* Serialises this class using cereal.
*
* @param[in] ar The archive to serialise to (or to serialise from).
*/
template<class Archive>
void serialize(Archive& archive)
{
archive(CEREAL_NVP(camera_type), CEREAL_NVP(frustum), CEREAL_NVP(r_x), CEREAL_NVP(r_y), CEREAL_NVP(r_z), CEREAL_NVP(t_x), CEREAL_NVP(t_y), CEREAL_NVP(screen_width), CEREAL_NVP(screen_height), CEREAL_NVP(focal_length));
};
};
/**
* Saves the rendering parameters for an image to a json file.
*
* @param[in] rendering_parameters An instance of class RenderingParameters.
* @param[in] filename The file to write.
* @throws std::runtime_error if unable to open the given file for writing.
*/
void save_rendering_parameters(RenderingParameters rendering_parameters, std::string filename)
{
std::ofstream file(filename);
if (file.fail()) {
throw std::runtime_error("Error opening file for writing: " + filename);
}
cereal::JSONOutputArchive output_archive(file);
output_archive(cereal::make_nvp("rendering_parameters", rendering_parameters));
}; };
/** /**
...@@ -108,7 +170,7 @@ cv::Mat to_mat(const glm::mat4x4& glm_matrix) ...@@ -108,7 +170,7 @@ cv::Mat to_mat(const glm::mat4x4& glm_matrix)
* glm::vec3 point_2d = glm::project(point_3d, view_model, ortho_projection, viewport); * glm::vec3 point_2d = glm::project(point_3d, view_model, ortho_projection, viewport);
* @endcode * @endcode
*/ */
glm::mat4x4 get_4x4_modelview_matrix(fitting::OrthographicRenderingParameters params) glm::mat4x4 get_4x4_modelview_matrix(fitting::RenderingParameters params)
{ {
// rotation order: RPY * P // rotation order: RPY * P
auto rot_mtx_x = glm::rotate(glm::mat4(1.0f), params.r_x, glm::vec3{ 1.0f, 0.0f, 0.0f }); auto rot_mtx_x = glm::rotate(glm::mat4(1.0f), params.r_x, glm::vec3{ 1.0f, 0.0f, 0.0f });
...@@ -126,7 +188,7 @@ glm::mat4x4 get_4x4_modelview_matrix(fitting::OrthographicRenderingParameters pa ...@@ -126,7 +188,7 @@ glm::mat4x4 get_4x4_modelview_matrix(fitting::OrthographicRenderingParameters pa
* This function is mainly used since the linear shape fitting fitting::fit_shape_to_landmarks_linear * This function is mainly used since the linear shape fitting fitting::fit_shape_to_landmarks_linear
* expects one of these 3x4 affine camera matrices, as well as render::extract_texture. * expects one of these 3x4 affine camera matrices, as well as render::extract_texture.
*/ */
cv::Mat get_3x4_affine_camera_matrix(fitting::OrthographicRenderingParameters params, int width, int height) cv::Mat get_3x4_affine_camera_matrix(fitting::RenderingParameters params, int width, int height)
{ {
auto view_model = to_mat(get_4x4_modelview_matrix(params)); auto view_model = to_mat(get_4x4_modelview_matrix(params));
auto ortho_projection = to_mat(glm::ortho(params.frustum.l, params.frustum.r, params.frustum.b, params.frustum.t)); auto ortho_projection = to_mat(glm::ortho(params.frustum.l, params.frustum.r, params.frustum.b, params.frustum.t));
...@@ -185,7 +247,7 @@ glm::vec4 get_opencv_viewport(int width, int height) ...@@ -185,7 +247,7 @@ glm::vec4 get_opencv_viewport(int width, int height)
* @param[in] height Height of the image (or viewport). * @param[in] height Height of the image (or viewport).
* @return The estimated model and camera parameters. * @return The estimated model and camera parameters.
*/ */
OrthographicRenderingParameters estimate_orthographic_camera(std::vector<cv::Vec2f> image_points, std::vector<cv::Vec4f> model_points, int width, int height) RenderingParameters estimate_orthographic_camera(std::vector<cv::Vec2f> image_points, std::vector<cv::Vec4f> model_points, int width, int height)
{ {
using cv::Mat; using cv::Mat;
assert(image_points.size() == model_points.size()); assert(image_points.size() == model_points.size());
...@@ -209,7 +271,7 @@ OrthographicRenderingParameters estimate_orthographic_camera(std::vector<cv::Vec ...@@ -209,7 +271,7 @@ OrthographicRenderingParameters estimate_orthographic_camera(std::vector<cv::Vec
// 'parameters' contains the solution now. // 'parameters' contains the solution now.
Frustum camera_frustum{ -1.0f * aspect * static_cast<float>(parameters[5]), 1.0f * aspect * static_cast<float>(parameters[5]), -1.0f * static_cast<float>(parameters[5]), 1.0f * static_cast<float>(parameters[5]) }; Frustum camera_frustum{ -1.0f * aspect * static_cast<float>(parameters[5]), 1.0f * aspect * static_cast<float>(parameters[5]), -1.0f * static_cast<float>(parameters[5]), 1.0f * static_cast<float>(parameters[5]) };
return OrthographicRenderingParameters{ static_cast<float>(parameters[0]), static_cast<float>(parameters[1]), static_cast<float>(parameters[2]), static_cast<float>(parameters[3]), static_cast<float>(parameters[4]), camera_frustum }; return RenderingParameters{ CameraType::Orthographic, camera_frustum, static_cast<float>(parameters[0]), static_cast<float>(parameters[1]), static_cast<float>(parameters[2]), static_cast<float>(parameters[3]), static_cast<float>(parameters[4]), width, height };
}; };
} /* namespace fitting */ } /* namespace fitting */
......
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