eos 1.4.0
Loading...
Searching...
No Matches
keyframe_merging.hpp
1/*
2 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 *
4 * File: include/eos/video/keyframe_merging.hpp
5 *
6 * Copyright 2018 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 KEYFRAME_MERGING_HPP_
23#define KEYFRAME_MERGING_HPP_
24
25#include "eos/core/Image_opencv_interop.hpp"
26#include "eos/morphablemodel/Blendshape.hpp"
27#include "eos/morphablemodel/MorphableModel.hpp"
28#include "eos/render/texture_extraction.hpp"
29#include "eos/video/Keyframe.hpp"
30
31#include "Eigen/Core"
32
33#include "opencv2/core/core.hpp"
34#include "opencv2/imgproc/imgproc.hpp"
35
36#include <cassert>
37#include <vector>
38
39namespace eos {
40namespace video {
41
65inline cv::Mat merge_weighted_mean(const std::vector<Keyframe<cv::Mat>>& keyframes,
66 const morphablemodel::MorphableModel& morphable_model,
67 const std::vector<morphablemodel::Blendshape>& blendshapes)
68{
69 assert(keyframes.size() >= 1);
70
71 using cv::Mat;
72 using Eigen::VectorXf;
73 using std::vector;
74
75 vector<Mat> isomaps;
76 for (const auto& frame_data : keyframes)
77 {
78 const VectorXf shape =
79 morphable_model.get_shape_model().draw_sample(frame_data.fitting_result.pca_shape_coefficients) +
80 morphablemodel::to_matrix(blendshapes) *
81 Eigen::Map<const Eigen::VectorXf>(frame_data.fitting_result.expression_coefficients.data(),
82 frame_data.fitting_result.expression_coefficients.size());
83 const auto mesh =
84 morphablemodel::sample_to_mesh(shape, {}, morphable_model.get_shape_model().get_triangle_list(),
85 {}, morphable_model.get_texture_coordinates());
86 const auto affine_camera_matrix = fitting::get_3x4_affine_camera_matrix(
87 frame_data.fitting_result.rendering_parameters, frame_data.frame.cols, frame_data.frame.rows);
88 const Mat isomap = core::to_mat(render::extract_texture(mesh, affine_camera_matrix, core::from_mat(frame_data.frame), true,
89 render::TextureInterpolation::NearestNeighbour, 1024));
90 isomaps.push_back(isomap);
91 }
92
93 // Now do the actual merging:
94 Mat r = Mat::zeros(isomaps[0].rows, isomaps[0].cols, CV_32FC1);
95 Mat g = Mat::zeros(isomaps[0].rows, isomaps[0].cols, CV_32FC1);
96 Mat b = Mat::zeros(isomaps[0].rows, isomaps[0].cols, CV_32FC1);
97 Mat accumulated_weight = Mat::zeros(isomaps[0].rows, isomaps[0].cols, CV_32FC1);
98 // Currently, this just uses the weights in the alpha channel for weighting - they contain only the
99 // view-angle. We should use the keyframe's score as well. Plus the area of the source triangle.
100 for (auto&& isomap : isomaps)
101 {
102 vector<Mat> channels;
103 cv::split(isomap, channels);
104 // channels[0].convertTo(channels[0], CV_32FC1);
105 // We could avoid this explicit temporary, but then we'd have to convert both matrices
106 // to CV_32FC1 first - and manually multiply with 1/255. Not sure which one is faster.
107 // If we do it like this, the add just becomes '+=' - so I think it's fine like this.
108 // The final formula is:
109 // b += chan_0 * alpha * 1/255; (and the same for g and r respectively)
110 Mat weighted_b, weighted_g, weighted_r;
111 // // we scale the weights from [0, 255] to [0, 1]:
112 cv::multiply(channels[0], channels[3], weighted_b, 1 / 255.0, CV_32FC1);
113 cv::multiply(channels[1], channels[3], weighted_g, 1 / 255.0, CV_32FC1);
114 cv::multiply(channels[2], channels[3], weighted_r, 1 / 255.0, CV_32FC1);
115 b += weighted_b;
116 g += weighted_g;
117 r += weighted_r;
118 channels[3].convertTo(channels[3], CV_32FC1); // needed for the '/ 255.0f' below to work
119 cv::add(accumulated_weight, channels[3] / 255.0f, accumulated_weight, cv::noArray(), CV_32FC1);
120 }
121 b = b.mul(1.0 / (accumulated_weight)); // divide by number of frames used too?
122 g = g.mul(1.0 / (accumulated_weight));
123 r = r.mul(1.0 / (accumulated_weight));
124
125 // Let's return accumulated_weight too: Normalise by num_isomaps * 255 (=maximum weight)
126 // This sets the returned weight to the average from all the isomaps. Maybe the maximum would make more
127 // sense? => Not returning anything for now.
128 // accumulated_weight = (accumulated_weight / isomaps.size()) * 255;
129
130 Mat merged_isomap;
131 cv::merge(vector<Mat>{b, g, r}, merged_isomap);
132 merged_isomap.convertTo(merged_isomap, CV_8UC3);
133 return merged_isomap;
134};
135
146inline double variance_of_laplacian(const cv::Mat& image)
147{
148 cv::Mat laplacian;
149 cv::Laplacian(image, laplacian, CV_64F);
150
151 cv::Scalar mu, sigma;
152 cv::meanStdDev(laplacian, mu, sigma);
153
154 const double focus_measure = sigma.val[0] * sigma.val[0];
155 return focus_measure;
156};
157
158} /* namespace video */
159} /* namespace eos */
160
161#endif /* KEYFRAME_MERGING_HPP_ */
A class representing a 3D Morphable Model, consisting of a shape- and colour (albedo) PCA model.
Definition: MorphableModel.hpp:73
const std::vector< std::array< double, 2 > > & get_texture_coordinates() const
Definition: MorphableModel.hpp:413
const PcaModel & get_shape_model() const
Definition: MorphableModel.hpp:125
Eigen::VectorXf draw_sample(RNG &engine, float sigma=1.0f) const
Definition: PcaModel.hpp:150
Image3u from_mat(const cv::Mat &image)
Definition: opencv_interop.hpp:98
Eigen::Matrix< float, 3, 4 > get_3x4_affine_camera_matrix(RenderingParameters params, int width, int height)
Creates a 3x4 affine camera matrix from given fitting parameters. The matrix transforms points direct...
Definition: RenderingParameters.hpp:337
Eigen::MatrixXf to_matrix(const std::vector< Blendshape > &blendshapes)
Copies the blendshapes into a matrix, with each column being a blendshape.
Definition: Blendshape.hpp:118
core::Mesh sample_to_mesh(const Eigen::VectorXf &shape_instance, const Eigen::VectorXf &color_instance, const std::vector< std::array< int, 3 > > &tvi, const std::vector< std::array< int, 3 > > &tci, const std::vector< std::array< double, 2 > > &texture_coordinates=std::vector< std::array< double, 2 > >(), const std::vector< std::array< int, 3 > > &texture_triangle_indices=std::vector< std::array< int, 3 > >())
Definition: MorphableModel.hpp:584
eos::core::Image4u extract_texture(const core::Mesh &mesh, Eigen::Matrix4f view_model_matrix, Eigen::Matrix4f projection_matrix, ProjectionType projection_type, const eos::core::Image4u &image, int texturemap_resolution=512)
Extracts the texture from the given image and returns a texture map.
Definition: texture_extraction.hpp:70
double variance_of_laplacian(const cv::Mat &image)
Computes the variance of laplacian of the given image or patch.
Definition: keyframe_merging.hpp:146
cv::Mat merge_weighted_mean(const std::vector< Keyframe< cv::Mat > > &keyframes, const morphablemodel::MorphableModel &morphable_model, const std::vector< morphablemodel::Blendshape > &blendshapes)
Extracts texture from each keyframe and merges them using a weighted mean.
Definition: keyframe_merging.hpp:65
Namespace containing all of eos's 3D model fitting functionality.
A keyframe selected by the fitting algorithm.
Definition: Keyframe.hpp:37