geolib2
DepthCamera.cpp
Go to the documentation of this file.
2 #include "geolib/Shape.h"
3 
4 #include <image_geometry/pinhole_camera_model.h>
5 
6 #include <array>
7 #include <vector>
8 
9 namespace geo {
10 
11 void DefaultRenderResult::renderPixel(int x, int y, float depth, int i_triangle) {
12  float old_depth = image_.at<float>(y, x);
13  if (old_depth == 0 || old_depth > depth) {
14  image_.at<float>(y, x) = depth;
15 
16  if (pointer_) {
17  pointer_map_[x][y] = pointer_;
18  }
19 
20  if (!triangle_map_.empty()) {
21  triangle_map_[x][y] = i_triangle;
22  }
23  }
24 }
25 
27 {
28 }
29 
30 DepthCamera::DepthCamera(uint width, uint height, double fx, double fy, double cx, double cy, double tx, double ty)
31 {
32  sensor_msgs::CameraInfo cam_info;
33  cam_info.D.resize(5, 0);
34  // Intrinsic camera matrix for the raw (distorted) images.
35  // [fx 0 cx]
36  // K = [ 0 fy cy]
37  // [ 0 0 1]
38  cam_info.K[0] = fx;
39  cam_info.K[1] = 0;
40  cam_info.K[2] = cx;
41  cam_info.K[3] = 0;
42  cam_info.K[4] = fy;
43  cam_info.K[5] = cy;
44  cam_info.K[6] = 0;
45  cam_info.K[7] = 0;
46  cam_info.K[8] = 1;
47 
48  // Rectification matrix (stereo cameras only)
49  cam_info.R[0] = 1;
50  cam_info.R[1] = 0;
51  cam_info.R[2] = 0;
52  cam_info.R[3] = 0;
53  cam_info.R[4] = 1;
54  cam_info.R[5] = 0;
55  cam_info.R[6] = 0;
56  cam_info.R[7] = 0;
57  cam_info.R[8] = 1;
58 
59  // Projection/camera matrix
60  // [fx' 0 cx' Tx]
61  // P = [ 0 fy' cy' Ty]
62  // [ 0 0 1 0]
63  cam_info.P[0] = fx;
64  cam_info.P[1] = 0;
65  cam_info.P[2] = cx;
66  cam_info.P[3] = tx;
67  cam_info.P[4] = 0;
68  cam_info.P[5] = fy;
69  cam_info.P[6] = cy;
70  cam_info.P[7] = ty;
71  cam_info.P[8] = 0;
72  cam_info.P[9] = 0;
73  cam_info.P[10] = 1;
74  cam_info.P[11] = 0;
75 
76  cam_info.width = width;
77  cam_info.height = height;
78  cam_model_.fromCameraInfo(cam_info);
79 }
80 
81 DepthCamera::DepthCamera(const image_geometry::PinholeCameraModel& cam_model)
82 {
83  initFromCamModel(cam_model);
84 }
85 
86 DepthCamera::DepthCamera(const sensor_msgs::CameraInfo& cam_info)
87 {
88  image_geometry::PinholeCameraModel cam_model;
89  cam_model.fromCameraInfo(cam_info);
90  initFromCamModel(cam_model);
91 }
92 
94 }
95 
96 void DepthCamera::initFromCamModel(const image_geometry::PinholeCameraModel& cam_model)
97 {
98  cam_model_ = cam_model;
99 }
100 
101 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
102 //
103 // RASTERIZATION
104 //
105 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
106 
107 RasterizeResult DepthCamera::rasterize(const Shape& shape, const Pose3D& cam_pose, const Pose3D& obj_pose, cv::Mat& image,
108  PointerMap& pointer_map, void* pointer, TriangleMap& triangle_map) const {
109  return rasterize(shape, cam_pose.inverse() * obj_pose, image, pointer_map, pointer, triangle_map);
110 }
111 
112 // -------------------------------------------------------------------------------
113 
114 RasterizeResult DepthCamera::rasterize(const Shape& shape, const Pose3D& pose, cv::Mat& image,
115  PointerMap& pointer_map, void* pointer, TriangleMap& triangle_map) const {
116 
117  RenderOptions opt;
118  opt.setMesh(shape.getMesh(), pose);
119 
120  DefaultRenderResult res(image, pointer, pointer_map, triangle_map);
121 
122  render(opt, res);
123 
124  return RasterizeResult();
125 }
126 
127 // -------------------------------------------------------------------------------
128 
129 void DepthCamera::render(const RenderOptions& opt, RenderResult& res) const {
130  const Mesh& mesh = *opt.mesh_;
131  const Pose3D& pose = opt.pose_;
132 
133  if (mesh.getMaxRadius() < pose.getOrigin().z) {
134  return;
135  }
136 
137  const std::vector<geo::TriangleI>& triangles = mesh.getTriangleIs();
138  const std::vector<geo::Vec3d>& points = mesh.getPoints();
139 
140  // transform points
141  std::vector<geo::Vec3d> points_t(points.size());
142  std::vector<bool> points_t_in_view(points.size());
143  std::vector<cv::Point2f> points_2d(points.size());
144 
145  // Do not render in case no point of the mesh is inside the field of view
146  bool in_view = false;
147  for (unsigned int i = 0; i < points.size(); ++i) {
148  points_t[i] = pose * points[i];
149  points_t_in_view[i] = (points_t[i].z < near_clip_z_);
150  points_2d[i] = project3Dto2D<double, float>(points_t[i]);
151  if (!in_view && points_t_in_view[i])
152  {
153  in_view = true;
154  }
155  }
156  if (!in_view)
157  return;
158 
159  uint i_triangle = 0;
160  for(std::vector<TriangleI>::const_iterator it_tri = triangles.cbegin(); it_tri != triangles.cend(); ++it_tri) {
161 
162  const geo::Vec3d& p1_3d = points_t[it_tri->i1_];
163  const geo::Vec3d& p2_3d = points_t[it_tri->i2_];
164  const geo::Vec3d& p3_3d = points_t[it_tri->i3_];
165 
166  uchar n_verts_in = 0;
167  bool v1_in = false;
168  bool v2_in = false;
169  // bool v3_in = false; // Not used, because of logic can be concluded this would be true or false
171 
172  if (points_t_in_view[it_tri->i1_]) {
173  ++n_verts_in;
174  v1_in = true;
175  }
176 
177  if (points_t_in_view[it_tri->i2_]) {
178  ++n_verts_in;
179  v2_in = true;
180  }
181 
182  if (points_t_in_view[it_tri->i3_]) {
183  ++n_verts_in;
184  // v3_in = true; // Not used, because of logic can be concluded this would be true or false
185  }
186 
187  if (n_verts_in == 1) {
188  if (v1_in) { vIn[0] = &(p1_3d); vIn[1] = &(p2_3d); vIn[2] = &(p3_3d); }
189  else if (v2_in) { vIn[0] = &(p2_3d); vIn[1] = &(p3_3d); vIn[2] = &(p1_3d); }
190  else { vIn[0] = &(p3_3d); vIn[1] = &(p1_3d); vIn[2] = &(p2_3d); } // if (v3_in)
191 
192  //Parametric line stuff
193  // p = v0 + v01*t
194  geo::Vec3d v01 = *vIn[1] - *vIn[0];
195 
196  float t1 = ((near_clip_z_ - vIn[0]->z) / v01.z);
197 
198  geo::Vec3d new2(vIn[0]->x + v01.x * t1, vIn[0]->y + v01.y * t1, near_clip_z_);
199 
200  // Second vert point
201  geo::Vec3d v02 = *vIn[2] - *vIn[0];
202 
203  float t2 = ((near_clip_z_ - vIn[0]->z) / v02.z);
204 
205  geo::Vec3d new3(vIn[0]->x + v02.x * t2, vIn[0]->y + v02.y * t2, near_clip_z_);
206 
207  drawTriangle<double, float>(*vIn[0], new2, new3, opt, res, i_triangle);
208  } else if (n_verts_in == 2) {
209  if (!v1_in) { vIn[0]=&(p2_3d); vIn[1]=&(p3_3d); vIn[2]=&(p1_3d); }
210  else if (!v2_in) { vIn[0]=&(p3_3d); vIn[1]=&(p1_3d); vIn[2]=&(p2_3d); }
211  else { vIn[0]=&(p1_3d); vIn[1]=&(p2_3d); vIn[2]=&(p3_3d); } // if (!v3_in)
212 
213  //Parametric line stuff
214  // p = v0 + v01*t
215  geo::Vec3d v01 = *vIn[2] - *vIn[0];
216 
217  float t1 = ((near_clip_z_ - vIn[0]->z)/v01.z);
218 
219  geo::Vec3d new2(vIn[0]->x + v01.x * t1,vIn[0]->y + v01.y * t1, near_clip_z_);
220 
221  // Second point
222  geo::Vec3d v02 = *vIn[2] - *vIn[1];
223 
224  float t2 = ((near_clip_z_ - vIn[1]->z)/v02.z);
225 
226  geo::Vec3d new3(vIn[1]->x + v02.x * t2, vIn[1]->y + v02.y * t2, near_clip_z_);
227 
228  drawTriangle<double, float>(*vIn[0], *vIn[1], new2, opt, res, i_triangle);
229 
230  drawTriangle<double, float>(new2, *vIn[1], new3, opt, res, i_triangle);
231 
232  } else if (n_verts_in == 3) {
233  const cv::Point2f& p1_2d = points_2d[it_tri->i1_];
234  const cv::Point2f& p2_2d = points_2d[it_tri->i2_];
235  const cv::Point2f& p3_2d = points_2d[it_tri->i3_];
236 
237  drawTriangle2D<float>(geo::Vec3f(p1_2d.x, p1_2d.y, 1.0f / -p1_3d.z),
238  geo::Vec3f(p2_2d.x, p2_2d.y, 1.0f / -p2_3d.z),
239  geo::Vec3f(p3_2d.x, p3_2d.y, 1.0f / -p3_3d.z),
240  opt, res, i_triangle);
241  }
242 
243  if (res.stop_) {
244  return;
245  }
246 
247  ++i_triangle;
248  }
249 }
250 
251 // -------------------------------------------------------------------------------
252 
253 template<typename Tin, typename Tout>
254 void DepthCamera::drawTriangle(const geo::Vec3T<Tin>& p1_3d, const geo::Vec3T<Tin>& p2_3d, const geo::Vec3T<Tin>& p3_3d,
255  const RenderOptions& opt, RenderResult& res, uint i_triangle) const {
256  cv::Point_<Tout> p1_2d = project3Dto2D<Tin, Tout>(p1_3d);
257  cv::Point_<Tout> p2_2d = project3Dto2D<Tin, Tout>(p2_3d);
258  cv::Point_<Tout> p3_2d = project3Dto2D<Tin, Tout>(p3_3d);
259 
260  drawTriangle2D<Tout>(geo::Vec3T<Tout>(p1_2d.x, p1_2d.y, 1.0f / -p1_3d.z),
261  geo::Vec3T<Tout>(p2_2d.x, p2_2d.y, 1.0f / -p2_3d.z),
262  geo::Vec3T<Tout>(p3_2d.x, p3_2d.y, 1.0f / -p3_3d.z),
263  opt, res, i_triangle);
264 }
265 
266 // -------------------------------------------------------------------------------
267 
268 template<typename T>
270  const RenderOptions& opt, RenderResult& res, uint i_triangle) const {
271 
272  if (!opt.back_face_culling_ || (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y) < 0) {
273 
274  int min_y = std::min<int>(p1.y, std::min<int>(p2.y, p3.y));
275  int max_y = std::max<int>(p1.y, std::max<int>(p2.y, p3.y));
276  int min_x = std::min<int>(p1.x, std::min<int>(p2.x, p3.x));
277  int max_x = std::max<int>(p1.x, std::max<int>(p2.x, p3.x));
278 
279  if (min_x < res.getWidth() && max_x > 0 && min_y < res.getHeight() && max_y > 0) {
280 
281  const geo::Vec3T<T>* p_min=&p1;
282  const geo::Vec3T<T>* p_mid=&p2;
283  const geo::Vec3T<T>* p_max=&p3;
284  if (min_y == max_y) {
285  sort(p_min, p_mid, p_max, 0);
286 
287  drawTrianglePart(p_min->y, p_mid->y,
288  p_min->x, 0, p_max->x, 0,
289  p_min->z, 0, p_max->z, 0,
290  opt, res, i_triangle);
291  } else {
292  sort(p_min, p_mid, p_max, 1);
293 
294  int y_min_mid = static_cast<int>(p_mid->y) - static_cast<int>(p_min->y);
295  int y_mid_max = static_cast<int>(p_max->y) - static_cast<int>(p_mid->y);
296  int y_min_max = static_cast<int>(p_max->y) - static_cast<int>(p_min->y);
297 
298  geo::Vec3T<T> p_prime = (y_mid_max * *p_min + y_min_mid * *p_max) / y_min_max;
299 
300  const geo::Vec3T<T>* p_a = &p_prime;
301  const geo::Vec3T<T>* p_b = p_mid;
302  if (p_prime.x > p_mid->x)
303  std::swap(p_a, p_b);
304 
305  drawTrianglePart(p_min->y, p_mid->y,
306  p_min->x, (p_a->x - p_min->x) / y_min_mid, p_min->x, (p_b->x - p_min->x) / y_min_mid,
307  p_min->z, (p_a->z - p_min->z) / y_min_mid, p_min->z, (p_b->z - p_min->z) / y_min_mid,
308  opt, res, i_triangle);
309 
310  drawTrianglePart(p_mid->y, p_max->y,
311  p_a->x, (p_max->x - p_a->x) / y_mid_max, p_b->x, (p_max->x - p_b->x) / y_mid_max,
312  p_a->z, (p_max->z - p_a->z) / y_mid_max, p_b->z, (p_max->z - p_b->z) / y_mid_max,
313  opt, res, i_triangle);
314 
315  }
316  }
317  }
318 }
319 
320 // -------------------------------------------------------------------------------
321 
322 void DepthCamera::drawTrianglePart(int y_start, int y_end,
323  float x_start, float x_start_delta, float x_end, float x_end_delta,
324  float d_start, float d_start_delta, float d_end, float d_end_delta,
325  const RenderOptions& /*opt*/, RenderResult& res, uint i_triangle) const {
326 
327  if (y_start < 0) {
328  d_start += d_start_delta * -y_start;
329  d_end += d_end_delta * -y_start;
330  x_start += x_start_delta * -y_start;
331  x_end += x_end_delta * -y_start;
332  y_start = 0;
333  }
334 
335  y_end = std::min(res.getHeight() - 1, y_end);
336 
337  for(int y = y_start; y <= y_end; ++y) {
338  float d = d_start;
339  float d_delta = (d_end - d_start) / (x_end - x_start);
340 
341  int x_start2;
342  if (x_start < 0) {
343  d += d_delta * -x_start;
344  x_start2 = 0;
345  } else {
346  x_start2 = x_start;
347  }
348 
349  int x_end2 = std::min(res.getWidth() - 1, (int)x_end);
350 
351  for(int x = x_start2; x <= x_end2; ++x) {
352  float depth = 1.0f / d;
353 
354  res.renderPixel(x, y, depth, i_triangle);
355  d += d_delta;
356  }
357 
358  d_start+= d_start_delta;
359  d_end += d_end_delta;
360  x_start += x_start_delta;
361  x_end += x_end_delta;
362  }
363 }
364 
365 // -------------------------------------------------------------------------------
366 
367 template<typename T>
368 void DepthCamera::sort(const geo::Vec3T<T>*& p_min, const geo::Vec3T<T>*& p_mid, const geo::Vec3T<T>*& p_max, uchar i) const
369 {
370  if (p_min->m[i] > p_max->m[i])
371  std::swap(p_min, p_max);
372 
373  if (p_min->m[i] > p_mid->m[i])
374  std::swap(p_min, p_mid);
375 
376  if (p_mid->m[i] > p_max->m[i])
377  std::swap(p_mid, p_max);
378 }
379 
380 }
geo::DepthCamera::near_clip_z_
static constexpr const double near_clip_z_
Definition: DepthCamera.h:249
Shape.h
geo::RenderResult::getWidth
int getWidth() const
Definition: DepthCamera.h:96
geo::RenderOptions::setMesh
void setMesh(const geo::Mesh &mesh, const geo::Pose3D &pose=geo::Pose3D::identity())
setMesh: set mesh to be rendered
Definition: DepthCamera.h:54
geo
Definition: Box.h:6
geo::Mesh::getTriangleIs
const std::vector< TriangleI > & getTriangleIs() const
Definition: Mesh.cpp:46
geo::DefaultRenderResult::renderPixel
virtual void renderPixel(int x, int y, float depth, int i_triangle)
Definition: DepthCamera.cpp:11
geo::DepthCamera::drawTriangle
void drawTriangle(const geo::Vec3T< Tin > &p1, const geo::Vec3T< Tin > &p2, const geo::Vec3T< Tin > &p3, const RenderOptions &opt, RenderResult &res, uint i_triangle) const
Definition: DepthCamera.cpp:254
geo::DefaultRenderResult::pointer_
void * pointer_
Definition: DepthCamera.h:143
geo::RenderOptions::pose_
Pose3D pose_
pose_ pose of the mesh with respect to the virtual camera
Definition: DepthCamera.h:71
geo::DepthCamera::~DepthCamera
virtual ~DepthCamera()
Definition: DepthCamera.cpp:93
vector
std::vector::size
T size(T... args)
geo::Transform3T::getOrigin
const Vec3T< T > & getOrigin() const
Definition: math_types.h:730
geo::Vec3T
Definition: math_types.h:13
geo::Vec3T::m
T m[3]
Definition: math_types.h:218
geo::DepthCamera::rasterize
RasterizeResult rasterize(const Shape &shape, const Pose3D &pose, cv::Mat &image, PointerMap &pointer_map=EMPTY_POINTER_MAP, void *pointer=0, TriangleMap &triangle_map=EMPTY_TRIANGLE_MAP) const
rasterize: render a 3D shape onto a 2D image
Definition: DepthCamera.cpp:114
geo::DepthCamera::render
void render(const RenderOptions &opt, RenderResult &res) const
Definition: DepthCamera.cpp:129
geo::Transform3T
Definition: math_types.h:19
geo::DepthCamera::initFromCamModel
void initFromCamModel(const image_geometry::PinholeCameraModel &cam_model)
Set camera parameters from pinhole camera model.
Definition: DepthCamera.cpp:96
geo::Mesh::getMaxRadius
double getMaxRadius() const
Definition: Mesh.cpp:125
geo::Shape::getMesh
virtual const Mesh & getMesh() const
return the mesh defining the shape
Definition: Shape.cpp:425
geo::RenderOptions::back_face_culling_
bool back_face_culling_
back_face_culling_ flag to optimise rendering mesh triangles facing away from the camera.
Definition: DepthCamera.h:76
geo::DepthCamera::drawTriangle2D
void drawTriangle2D(const geo::Vec3T< T > &p1, const geo::Vec3T< T > &p2, const geo::Vec3T< T > &p3, const RenderOptions &opt, RenderResult &res, uint i_triangle) const
Definition: DepthCamera.cpp:269
geo::RenderOptions::mesh_
const geo::Mesh * mesh_
mesh_ mesh to be rendered
Definition: DepthCamera.h:66
geo::DepthCamera::DepthCamera
DepthCamera()
Definition: DepthCamera.cpp:26
geo::Vec3T::y
T y
Definition: math_types.h:217
geo::Transform3T::inverse
Transform3T inverse() const
Definition: math_types.h:747
geo::Mesh::getPoints
const std::vector< geo::Vector3 > & getPoints() const
Definition: Mesh.cpp:42
geo::RenderResult::getHeight
int getHeight() const
Definition: DepthCamera.h:98
geo::RenderResult
Definition: DepthCamera.h:81
geo::RenderOptions
Definition: DepthCamera.h:41
geo::DefaultRenderResult::pointer_map_
PointerMap & pointer_map_
Definition: DepthCamera.h:144
geo::DepthCamera::sort
void sort(const geo::Vec3T< T > *&p_min, const geo::Vec3T< T > *&p_mid, const geo::Vec3T< T > *&p_max, uchar dim) const
Definition: DepthCamera.cpp:368
geo::DefaultRenderResult
Definition: DepthCamera.h:109
array
geo::RasterizeResult
Definition: DepthCamera.h:27
geo::DepthCamera::fy
double fy() const
Definition: DepthCamera.h:222
geo::DepthCamera::cam_model_
image_geometry::PinholeCameraModel cam_model_
Definition: DepthCamera.h:251
DepthCamera.h
std::swap
T swap(T... args)
std::min
T min(T... args)
geo::DefaultRenderResult::triangle_map_
TriangleMap & triangle_map_
Definition: DepthCamera.h:145
geo::DepthCamera::drawTrianglePart
void drawTrianglePart(int y_start, int y_end, float x_start, float x_start_delta, float x_end, float x_end_delta, float d_start, float d_start_delta, float d_end, float d_end_delta, const RenderOptions &opt, RenderResult &res, uint i_triangle) const
Definition: DepthCamera.cpp:322
std::vector::cbegin
T cbegin(T... args)
geo::Vec3T::z
T z
Definition: math_types.h:217
std::vector::empty
T empty(T... args)
geo::DepthCamera::cx
double cx() const
Definition: DepthCamera.h:225
std::vector::cend
T cend(T... args)
geo::DepthCamera::fx
double fx() const
Definition: DepthCamera.h:219
geo::DepthCamera::width
int width() const
Definition: DepthCamera.h:239
geo::DepthCamera::height
int height() const
Definition: DepthCamera.h:237
geo::Mesh
Definition: Mesh.h:25
geo::RenderResult::stop_
bool stop_
Definition: DepthCamera.h:102
geo::Vec3T::x
T x
Definition: math_types.h:217
geo::Shape
A geometric description of a shape.
Definition: Shape.h:19
geo::DepthCamera::cy
double cy() const
Definition: DepthCamera.h:228
geo::DefaultRenderResult::image_
cv::Mat & image_
Definition: DepthCamera.h:142
geo::RenderResult::renderPixel
virtual void renderPixel(int x, int y, float depth, int i_triangle)=0