Commit 4c088cce authored by patrikhuber's avatar patrikhuber

Removed duplicate functions, cleaned up minor formatting and added some documentation

parent 00595c3d
/* /*
* Eos - A 3D Morphable Model fitting library written in modern C++11/14. * Eos - A 3D Morphable Model fitting library written in modern C++11/14.
* *
* File: include/eos/render/texture_extraction.hpp * File: include/eos/render/texture_extraction.hpp
* *
* Copyright 2014, 2015 Patrik Huber * Copyright 2014, 2015 Patrik Huber
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#ifndef TEXTURE_EXTRACTION_HPP_ #ifndef TEXTURE_EXTRACTION_HPP_
#define TEXTURE_EXTRACTION_HPP_ #define TEXTURE_EXTRACTION_HPP_
#include "eos/render/Mesh.hpp" #include "eos/render/Mesh.hpp"
#include "eos/render/detail/render_detail.hpp"
#include "opencv2/core/core.hpp" #include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/imgproc/imgproc.hpp"
namespace eos { namespace eos {
namespace render { namespace render {
inline cv::Rect calculate_bounding_box(cv::Vec4f v0, cv::Vec4f v1, cv::Vec4f v2, int viewportWidth, int viewportHeight)
{
using std::min;
using std::max;
/* Old, producing artifacts:
t.minX = max(min(t.v0.position[0], min(t.v1.position[0], t.v2.position[0])), 0.0f);
t.maxX = min(max(t.v0.position[0], max(t.v1.position[0], t.v2.position[0])), (float)(viewportWidth - 1));
t.minY = max(min(t.v0.position[1], min(t.v1.position[1], t.v2.position[1])), 0.0f);
t.maxY = min(max(t.v0.position[1], max(t.v1.position[1], t.v2.position[1])), (float)(viewportHeight - 1));*/
int minX = max(min(floor(v0[0]), min(floor(v1[0]), floor(v2[0]))), 0.0f);
int maxX = min(max(ceil(v0[0]), max(ceil(v1[0]), ceil(v2[0]))), static_cast<float>(viewportWidth - 1));
int minY = max(min(floor(v0[1]), min(floor(v1[1]), floor(v2[1]))), 0.0f);
int maxY = min(max(ceil(v0[1]), max(ceil(v1[1]), ceil(v2[1]))), static_cast<float>(viewportHeight - 1));
return cv::Rect(minX, minY, maxX - minX, maxY - minY);
};
// Returns true if inside the tri or on the border /**
* Computes whether the given point is inside (or on the border of) the triangle
* formed out of the given three vertices.
*
* @param[in] point Point to check.
* @param[in] triV0 First vertex.
* @param[in] triV1 Second vertex.
* @param[in] triV2 Third vertex.
* @return Whether the point is inside the triangle.
*/
inline bool is_point_in_triangle(cv::Point2f point, cv::Point2f triV0, cv::Point2f triV1, cv::Point2f triV2) { inline bool is_point_in_triangle(cv::Point2f point, cv::Point2f triV0, cv::Point2f triV1, cv::Point2f triV2) {
/* See http://www.blackpawn.com/texts/pointinpoly/ */ // See http://www.blackpawn.com/texts/pointinpoly/
// Compute vectors // Compute vectors
cv::Point2f v0 = triV2 - triV0; cv::Point2f v0 = triV2 - triV0;
cv::Point2f v1 = triV1 - triV0; cv::Point2f v1 = triV1 - triV0;
...@@ -70,22 +64,10 @@ inline bool is_point_in_triangle(cv::Point2f point, cv::Point2f triV0, cv::Point ...@@ -70,22 +64,10 @@ inline bool is_point_in_triangle(cv::Point2f point, cv::Point2f triV0, cv::Point
return (u >= 0) && (v >= 0) && (u + v < 1); return (u >= 0) && (v >= 0) && (u + v < 1);
}; };
inline bool are_vertices_cc_in_screen_space(const cv::Vec4f& v0, const cv::Vec4f& v1, const cv::Vec4f& v2) /**
{ * The interpolation types that can be used to map the
float dx01 = v1[0] - v0[0]; * texture from the original image to the isomap.
float dy01 = v1[1] - v0[1]; */
float dx02 = v2[0] - v0[0];
float dy02 = v2[1] - v0[1];
return (dx01*dy02 - dy01*dx02 < 0.0f); // Original: (dx01*dy02 - dy01*dx02 > 0.0f). But: OpenCV has origin top-left, y goes down
};
inline double implicit_line(float x, float y, const cv::Vec4f& v1, const cv::Vec4f& v2)
{
return ((double)v1[1] - (double)v2[1])*(double)x + ((double)v2[0] - (double)v1[0])*(double)y + (double)v1[0] * (double)v2[1] - (double)v2[0] * (double)v1[1];
};
// enum of transformation types used in mapping
enum class TextureInterpolation { enum class TextureInterpolation {
NearestNeighbour, NearestNeighbour,
Bilinear, Bilinear,
...@@ -93,21 +75,20 @@ enum class TextureInterpolation { ...@@ -93,21 +75,20 @@ enum class TextureInterpolation {
}; };
/** /**
* extracts the texture of the face from the image * Extracts the texture of the face from the given image
* and stores it as isomap (a rectangular texture map).
* *
* * @param[in] mesh A mesh with texture coordinates.
* @param[in] mesh TODO * @param[in] mvp_matrix An estimated 3x4 affine camera matrix.
* @param[in] mvp_matrix Atm working with a 4x4 (full) affine. But anything would work, just take care with the w-division. * @param[in] viewport_width Screen width.
* @param[in] viewport_width TODO * @param[in] viewport_height Screen height.
* @param[in] viewport_height TODO * @param[in] image The image to extract the texture from.
* @param[in] image Where to extract the texture from * @param[in] depth_buffer A precalculated depthbuffer image.
* @param[in] depth_buffer TODO note: We could also pass an instance of a Renderer here. Depending on how "stateful" the renderer is, this might make more sense. * @param[in] mapping_type The interpolation type to be used for the extraction.
* @param[in] mapping_type Which Transformation type to use for mapping * @return The extracted texture as isomap (texture map).
* @return A Mat with the texture as an isomap
* // note: framebuffer should have size of the image (ok not necessarily. What about mobile?) (well it should, to get optimal quality (and everywhere the same quality)?)
*/ */
inline cv::Mat extract_texture(Mesh mesh, cv::Mat mvp_matrix, int viewport_width, int viewport_height, cv::Mat image, cv::Mat depth_buffer, TextureInterpolation mapping_type) { inline cv::Mat extract_texture(Mesh mesh, cv::Mat mvp_matrix, int viewport_width, int viewport_height, cv::Mat image, cv::Mat depth_buffer, TextureInterpolation mapping_type)
{
using cv::Mat; using cv::Mat;
using cv::Vec4f; using cv::Vec4f;
using cv::Vec2f; using cv::Vec2f;
...@@ -149,11 +130,11 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat mvp_matrix, int viewport_width ...@@ -149,11 +130,11 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat mvp_matrix, int viewport_width
// Todo: This is all very similar to processProspectiveTri(...), except the other function does texturing stuff as well. Remove code duplication! // Todo: This is all very similar to processProspectiveTri(...), except the other function does texturing stuff as well. Remove code duplication!
//if (doBackfaceCulling) { //if (doBackfaceCulling) {
if (!are_vertices_cc_in_screen_space(v0, v1, v2)) if (!detail::are_vertices_ccw_in_screen_space(v0, v1, v2))
continue; continue;
//} //}
cv::Rect bbox = calculate_bounding_box(v0, v1, v2, viewport_width, viewport_height); cv::Rect bbox = detail::calculate_clipped_bounding_box(v0, v1, v2, viewport_width, viewport_height);
int minX = bbox.x; int minX = bbox.x;
int maxX = bbox.x + bbox.width; int maxX = bbox.x + bbox.width;
int minY = bbox.y; int minY = bbox.y;
...@@ -171,13 +152,13 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat mvp_matrix, int viewport_width ...@@ -171,13 +152,13 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat mvp_matrix, int viewport_width
float x = (float)xi + 0.5f; float x = (float)xi + 0.5f;
float y = (float)yi + 0.5f; float y = (float)yi + 0.5f;
// these will be used for barycentric weights computation // these will be used for barycentric weights computation
double one_over_v0ToLine12 = 1.0 / implicit_line(v0[0], v0[1], v1, v2); double one_over_v0ToLine12 = 1.0 / detail::implicit_line(v0[0], v0[1], v1, v2);
double one_over_v1ToLine20 = 1.0 / implicit_line(v1[0], v1[1], v2, v0); double one_over_v1ToLine20 = 1.0 / detail::implicit_line(v1[0], v1[1], v2, v0);
double one_over_v2ToLine01 = 1.0 / implicit_line(v2[0], v2[1], v0, v1); double one_over_v2ToLine01 = 1.0 / detail::implicit_line(v2[0], v2[1], v0, v1);
// affine barycentric weights // affine barycentric weights
double alpha = implicit_line(x, y, v1, v2) * one_over_v0ToLine12; double alpha = detail::implicit_line(x, y, v1, v2) * one_over_v0ToLine12;
double beta = implicit_line(x, y, v2, v0) * one_over_v1ToLine20; double beta = detail::implicit_line(x, y, v2, v0) * one_over_v1ToLine20;
double gamma = implicit_line(x, y, v0, v1) * one_over_v2ToLine01; double gamma = detail::implicit_line(x, y, v0, v1) * one_over_v2ToLine01;
// if pixel (x, y) is inside the triangle or on one of its edges // if pixel (x, y) is inside the triangle or on one of its edges
if (alpha >= 0 && beta >= 0 && gamma >= 0) if (alpha >= 0 && beta >= 0 && gamma >= 0)
{ {
......
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