eos  0.7.1
utils.hpp
1 /*
2  * Eos - A 3D Morphable Model fitting library written in modern C++11/14.
3  *
4  * File: include/eos/render/utils.hpp
5  *
6  * Copyright 2014, 2015 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 RENDER_UTILS_HPP_
23 #define RENDER_UTILS_HPP_
24 
25 #include "eos/render/Mesh.hpp"
26 
27 #include "opencv2/core/core.hpp"
28 #include "opencv2/imgproc/imgproc.hpp"
29 
30 namespace eos {
31  namespace render {
32 
50 inline cv::Vec2f clip_to_screen_space(const cv::Vec2f& clip_coordinates, int screen_width, int screen_height)
51 {
52  // Window transform:
53  const float x_ss = (clip_coordinates[0] + 1.0f) * (screen_width / 2.0f);
54  const float y_ss = screen_height - (clip_coordinates[1] + 1.0f) * (screen_height / 2.0f); // also flip y; Qt: Origin top-left. OpenGL: bottom-left.
55  return cv::Vec2f(x_ss, y_ss);
56  /* Note: What we do here is equivalent to
57  x_w = (x * vW/2) + vW/2;
58  However, Shirley says we should do:
59  x_w = (x * vW/2) + (vW-1)/2;
60  (analogous for y)
61  Todo: Check the consequences.
62  */
63 };
64 
76 inline cv::Vec2f screen_to_clip_space(const cv::Vec2f& screen_coordinates, int screen_width, int screen_height)
77 {
78  const float x_cs = screen_coordinates[0] / (screen_width / 2.0f) - 1.0f;
79  float y_cs = screen_coordinates[1] / (screen_height / 2.0f) - 1.0f;
80  y_cs *= -1.0f;
81  return cv::Vec2f(x_cs, y_cs);
82 };
83 
95 cv::Vec3f calculate_face_normal(const cv::Vec3f& v0, const cv::Vec3f& v1, const cv::Vec3f& v2)
96 {
97  cv::Vec3f n = (v1 - v0).cross(v2 - v0); // v0-to-v1 x v0-to-v2
98  n /= cv::norm(n);
99  return n;
100 };
101 
111 cv::Mat draw_texcoords(Mesh mesh, cv::Mat image = cv::Mat())
112 {
113  using cv::Point2f;
114  using cv::Scalar;
115  if (image.empty())
116  {
117  image = cv::Mat(512, 512, CV_8UC4, Scalar(0.0f, 0.0f, 0.0f, 255.0f));
118  }
119 
120  for (const auto& triIdx : mesh.tvi) {
121  cv::line(image, Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
122  cv::line(image, Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
123  cv::line(image, Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
124  }
125  return image;
126 };
127 
128 // TODO: Should go to detail:: namespace, or texturing/utils or whatever.
129 unsigned int get_max_possible_mipmaps_num(unsigned int width, unsigned int height)
130 {
131  unsigned int mipmapsNum = 1;
132  unsigned int size = std::max(width, height);
133 
134  if (size == 1)
135  return 1;
136 
137  do {
138  size >>= 1;
139  mipmapsNum++;
140  } while (size != 1);
141 
142  return mipmapsNum;
143 };
144 
145 inline bool is_power_of_two(int x)
146 {
147  return !(x & (x - 1));
148 };
149 
156 class Texture
157 {
158 public:
159  std::vector<cv::Mat> mipmaps; // make Texture a friend class of renderer, then move this to private?
160  unsigned char widthLog, heightLog; // log2 of width and height of the base mip-level
161 
162 //private:
163  //std::string filename;
164  unsigned int mipmaps_num;
165 };
166 
167 // throws: ocv exc, runtime_ex
168 Texture create_mipmapped_texture(cv::Mat image, unsigned int mipmapsNum = 0) {
169  assert(image.type() == CV_8UC3 || image.type() == CV_8UC4);
170 
171  Texture texture;
172 
173  texture.mipmaps_num = (mipmapsNum == 0 ? get_max_possible_mipmaps_num(image.cols, image.rows) : mipmapsNum);
174  /*if (mipmapsNum == 0)
175  {
176  uchar mmn = render::utils::MatrixUtils::getMaxPossibleMipmapsNum(image.cols, image.rows);
177  this->mipmapsNum = mmn;
178  } else
179  {
180  this->mipmapsNum = mipmapsNum;
181  }*/
182 
183  if (texture.mipmaps_num > 1)
184  {
185  if (!is_power_of_two(image.cols) || !is_power_of_two(image.rows))
186  {
187  throw std::runtime_error("Error: Couldn't generate mipmaps, width or height not power of two.");
188  }
189  }
190  if (image.type() == CV_8UC3)
191  {
192  image.convertTo(image, CV_8UC4); // Most often, the input img is CV_8UC3. Img is BGR. Add an alpha channel
193  cv::cvtColor(image, image, CV_BGR2BGRA);
194  }
195 
196  int currWidth = image.cols;
197  int currHeight = image.rows;
198  std::vector<cv::Mat> mipmaps;
199  for (int i = 0; i < texture.mipmaps_num; i++)
200  {
201  if (i == 0) {
202  mipmaps.push_back(image);
203  }
204  else {
205  cv::Mat currMipMap(currHeight, currWidth, CV_8UC4);
206  cv::resize(mipmaps[i - 1], currMipMap, currMipMap.size());
207  mipmaps.push_back(currMipMap);
208  }
209 
210  if (currWidth > 1)
211  currWidth >>= 1;
212  if (currHeight > 1)
213  currHeight >>= 1;
214  }
215  texture.mipmaps = mipmaps;
216  texture.widthLog = (uchar)(std::log(mipmaps[0].cols) / CV_LOG2 + 0.0001f); // std::epsilon or something? or why 0.0001f here?
217  texture.heightLog = (uchar)(std::log(mipmaps[0].rows) / CV_LOG2 + 0.0001f); // Changed std::logf to std::log because it doesnt compile in linux (gcc 4.8). CHECK THAT
218  return texture;
219 };
220 
221  } /* namespace render */
222 } /* namespace eos */
223 
224 #endif /* RENDER_UTILS_HPP_ */
cv::Vec3f calculate_face_normal(const cv::Vec3f &v0, const cv::Vec3f &v1, const cv::Vec3f &v2)
Definition: utils.hpp:95
Represents a texture for rendering.
Definition: utils.hpp:156
std::pair< cv::Mat, cv::Mat > render(Mesh mesh, cv::Mat model_view_matrix, cv::Mat projection_matrix, int viewport_width, int viewport_height, const boost::optional< Texture > &texture=boost::none, bool enable_backface_culling=false, bool enable_near_clipping=true, bool enable_far_clipping=true)
Definition: render.hpp:125
cv::Mat draw_texcoords(Mesh mesh, cv::Mat image=cv::Mat())
Definition: utils.hpp:111
cv::Vec2f screen_to_clip_space(const cv::Vec2f &screen_coordinates, int screen_width, int screen_height)
Definition: utils.hpp:76
Namespace containing all of eos&#39;s 3D model fitting functionality.
cv::Vec2f clip_to_screen_space(const cv::Vec2f &clip_coordinates, int screen_width, int screen_height)
Definition: utils.hpp:50
This class represents a 3D mesh consisting of vertices, vertex colour information and texture coordin...
Definition: Mesh.hpp:45
std::vector< std::array< int, 3 > > tvi
Triangle vertex indices.
Definition: Mesh.hpp:51
std::vector< cv::Vec2f > texcoords
Texture coordinates for each vertex.
Definition: Mesh.hpp:49