1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "viewer.h"
28
29#include <easy3d/core/point_cloud.h>
30#include <easy3d/renderer/opengl.h>
31#include <easy3d/renderer/drawable_points.h>
32#include <easy3d/renderer/drawable_lines.h>
33#include <easy3d/renderer/camera.h>
34#include <easy3d/renderer/manipulated_camera_frame.h>
35#include <easy3d/renderer/texture_manager.h>
36#include <easy3d/renderer/shape.h>
37#include <easy3d/renderer/renderer.h>
38#include <easy3d/renderer/shader_program.h>
39#include <easy3d/renderer/shader_manager.h>
40#include <easy3d/renderer/transform.h>
41#include <easy3d/util/string.h>
42#include <easy3d/util/file_system.h>
43#include <easy3d/util/resource.h>
44
45
47
48
49
50const float scale = 0.3f;
51
52TutorialRealCamera::TutorialRealCamera(const std::string& title,
53 const std::string& bundler_file,
54 const std::string& cloud_file)
55 :
Viewer(title, 4, 3, 2, false, false)
56 , current_view_(0)
57 , texture_(nullptr)
58 , cameras_drawable_(nullptr)
59 , ray_drawable_(nullptr)
60 , cross_drawable_(nullptr)
61{
62
63 if (add_model(cloud_file)) {
64 auto drawable = current_model()->renderer()->get_points_drawable("vertices");
65 drawable->set_point_size(5.0f);
66
67
68 if (read_bundler_file(bundler_file))
69 update_cameras_drawable(true);
70 else
71 LOG(ERROR) << "failed to load bundler file";
72
73 camera()->setUpVector(
vec3(0, 1, 0));
74 camera()->setViewDirection(
vec3(0, 0, -1));
75 camera_->showEntireScene();
76 }
77 else
78 LOG(ERROR) << "failed to load point cloud";
79
80 hint_ = "Press 'Space' to switch views \n"
81 "Press 'h' to show/hide the cameras \n"
82 "Move cursor on image to show corresponding 3D ray \n"
83 "Move cursor on scene to show corresponding image point";
84}
85
86
87bool TutorialRealCamera::key_press_event(int key, int modifiers) {
88 if (ray_drawable_)
89 ray_drawable_->set_visible(false);
90 if (cross_drawable_)
91 cross_drawable_->set_visible(false);
92
93 if (key == KEY_SPACE) {
94 if (!views_.empty()) {
95 current_view_ = (current_view_ + 1) % static_cast<int>(views_.size());
96 const bool ground_truth = true;
97 if (KRT_to_camera(current_view_, camera(), ground_truth)) {
98 update_cameras_drawable(ground_truth);
99 std::cout << "----- view " << current_view_ << ": " << (ground_truth ? "ground truth view" : "calibration view") << std::endl;
100 set_title("TutorialRealCamera: View_" + std::to_string(current_view_));
101 const CameraPara &c = views_[current_view_];
102
103 resize(static_cast<int>(static_cast<float>(c.w) * scale), static_cast<int>(static_cast<float>(c.h) * scale));
104 }
105 }
106 return true;
107 }
108 else if (key == KEY_1) {
109 if (!views_.empty()) {
110 const bool ground_truth = false;
111 if (KRT_to_camera(current_view_, camera(), ground_truth)) {
112 update_cameras_drawable(ground_truth);
113 std::cout << "----- view " << current_view_ << ": " << (ground_truth ? "ground truth view" : "calibration view") << std::endl;
114 set_title("TutorialRealCamera: View_" + std::to_string(current_view_));
115 const CameraPara &c = views_[current_view_];
116
117 resize(static_cast<int>(static_cast<float>(c.w) * scale), static_cast<int>(static_cast<float>(c.h) * scale));
118 }
119 }
120 return true;
121 }
122 else if (key == KEY_2) {
123 if (!views_.empty()) {
124 const bool ground_truth = true;
125 if (KRT_to_camera(current_view_, camera(), ground_truth)) {
126 update_cameras_drawable(ground_truth);
127 std::cout << "----- view " << current_view_ << ": " << (ground_truth ? "ground truth view" : "calibration view") << std::endl;
128 set_title("TutorialRealCamera: View_" + std::to_string(current_view_));
129 const CameraPara &c = views_[current_view_];
130
131 resize(static_cast<int>(static_cast<float>(c.w) * scale), static_cast<int>(static_cast<float>(c.h) * scale));
132 }
133 }
134 return true;
135 }
136 else if (key == KEY_H) {
137 if (cameras_drawable_) {
138 cameras_drawable_->set_visible(!cameras_drawable_->is_visible());
139 update();
140 }
141 return true;
142 }
143 else
144 return Viewer::key_press_event(key, modifiers);
145}
146
147
148void TutorialRealCamera::load_image() {
152 }
153 update();
154}
155
156
157bool TutorialRealCamera::KRT_to_camera(
int view_index,
Camera* c,
bool ground_truth) {
158 if (view_index < 0 || view_index >= views_.size()) {
159 std::cerr << "Error: invalid view index (" << view_index << ")" << std::endl;
160 return false;
161 }
162
163 const CameraPara& cam = views_[view_index];
164
165 if (ground_truth) {
166
170 const float proj11 = 2.0f * cam.fy / static_cast<float>(cam.h);
171 const float fov = 2.0f * std::atan(1.0f / proj11);
173 }
174 else {
176 cam.fx, cam.fy, 0.0f,
177 cam.cx, cam.cy,
178 cam.R, cam.t, true);
179 }
180
181 load_image();
182
183 return true;
184}
185
186
187void TutorialRealCamera::update_cameras_drawable(bool ground_truth)
188{
189 if (!cameras_drawable_) {
191 add_drawable(std::shared_ptr<LinesDrawable>(cameras_drawable_));
192 cameras_drawable_->set_uniform_coloring(
vec4(0, 0, 1, 1.0f));
193 cameras_drawable_->set_line_width(2.0f);
194 }
195
196 std::vector<vec3> vertices;
197 for (std::size_t i = 0; i < views_.size(); ++i) {
199 KRT_to_camera(static_cast<int>(i), &c, ground_truth);
200 std::vector<vec3> points;
203 for (auto& p : points)
204 vertices.push_back(m * p);
205 }
206
207 cameras_drawable_->update_vertex_buffer(vertices);
208}
209
210
211Rect TutorialRealCamera::calculate_image_rect()
const {
212 if (texture_ == nullptr) {
213 LOG_N_TIMES(3, ERROR) << "image not shown";
214 return {0, 0, 0, 0};
215 }
216
217 int tex_w = texture_->width();
218 int tex_h = texture_->height();
219 const float image_as = static_cast<float>(tex_w) / static_cast<float>(tex_h);
220 const float viewer_as = static_cast<float>(width()) / static_cast<float>(height());
221 if (image_as < viewer_as) {
222 tex_h = static_cast<int>(static_cast<float>(height()) * scale);
223 tex_w = static_cast<int>(static_cast<float>(tex_h) * image_as);
224 }
225 else {
226 tex_w = static_cast<int>(static_cast<float>(width()) * scale);
227 tex_h = static_cast<int>(static_cast<float>(tex_w) / image_as);
228 }
229
230 const int x = 20.0f;
231 const int y = 120.0f;
232 return Rect(x, x +
static_cast<float>(tex_w), y, y +
static_cast<float>(tex_h));
233}
234
235
236void TutorialRealCamera::post_draw() {
237 if (texture_ == nullptr)
238 return;
239
240 const Rect image_rect = calculate_image_rect();
241 const Rect quad(image_rect.
x_min() * dpi_scaling(), image_rect.
x_max() * dpi_scaling(),
242 image_rect.
y_min() * dpi_scaling(), image_rect.
y_max() * dpi_scaling());
243
244 const int w = static_cast<int>(static_cast<float>(width()) * dpi_scaling());
245 const int h = static_cast<int>(static_cast<float>(height()) * dpi_scaling());
248
249 if (cross_drawable_ && cross_drawable_->is_visible()) {
251 if (!program) {
252 std::vector<ShaderProgram::Attribute> attributes;
256 }
257 if (!program)
258 return;
259
260 const mat4 &proj =
transform::ortho(0.0f,
static_cast<float>(width()),
static_cast<float>(height()), 0.0f,
261 0.0f, -1.0f);
262 glDisable(GL_DEPTH_TEST);
267 cross_drawable_->gl_draw();
269 glEnable(GL_DEPTH_TEST);
270 }
271
272 Viewer::post_draw();
273}
274
275
276bool TutorialRealCamera::mouse_free_move_event(int x, int y, int dx, int dy, int modifiers) {
277 (void) dx;
278 (void) dy;
279 (void) modifiers;
280
281 if (current_view_ < 0 || current_view_ >= views_.size()) {
282 std::cerr << "Error: invalid view index (" << current_view_ << ")" << std::endl;
283 return false;
284 }
285
286 const CameraPara &cam = views_[current_view_];
287 const Rect image_rect = calculate_image_rect();
288
289 if (
static_cast<float>(x) >= image_rect.
x_min() &&
static_cast<float>(x) <= image_rect.
x_max() &&
static_cast<float>(y) >= image_rect.
y_min() &&
static_cast<float>(y) <= image_rect.
y_max()) {
290 const float image_x = (
static_cast<float>(x) - image_rect.
x_min()) / image_rect.
width() *
static_cast<float>(cam.w);
291 const float image_y = (
static_cast<float>(y) - image_rect.
y_min()) / image_rect.
height() *
static_cast<float>(cam.h);
292 if (!ray_drawable_) {
294 add_drawable(std::shared_ptr<LinesDrawable>(ray_drawable_));
295 ray_drawable_->set_uniform_coloring(
vec4(0, 1, 0, 1.0f));
296 ray_drawable_->set_line_width(3.0f);
298 }
299 const vec3 pos = camera_pos(cam.R, cam.t);
300 const vec3 dir = pixel_to_ray(
static_cast<int>(image_x),
static_cast<int>(image_y), cam.fx, cam.fy, 0, cam.cx, cam.cy, cam.R, cam.t,
true);
301 const std::vector<vec3> points = {pos, pos + dir};
302 ray_drawable_->update_vertex_buffer(points);
303 ray_drawable_->set_visible(true);
304 update();
305 } else {
306 if (ray_drawable_)
307 ray_drawable_->set_visible(false);
308
309 bool found(false);
310 const vec3 p = point_under_pixel(x, y, found);
311 if (found) {
312 const vec2 q = point_to_pixel(p, cam.fx, cam.fy, 0, cam.cx, cam.cy, cam.R, cam.t);
313
314
315 if (q.x >= 0 && q.x <= static_cast<float>(cam.w) && q.y >= 0 && q.y <= static_cast<float>(cam.h)) {
316 const float screen_x = q.x /
static_cast<float>(cam.w) * image_rect.
width() + image_rect.
x_min();
317 const float screen_y = q.y /
static_cast<float>(cam.h) * image_rect.
height() + image_rect.
y_min();
318 if (!cross_drawable_) {
320 add_drawable(std::shared_ptr<LinesDrawable>(cross_drawable_));
321 cross_drawable_->set_line_width(3.0f);
322 }
323
324#if defined(__APPLE__)
325 const float size = 10;
326#else
327 const float size = static_cast<float>(10 * dpi_scaling());
328#endif
329 const std::vector<vec3> points = {
330 vec3(screen_x - size, screen_y, 0.5f),
vec3(screen_x + size, screen_y, 0.5f),
331 vec3(screen_x, screen_y - size, 0.5f),
vec3(screen_x, screen_y + size, 0.5f)
332 };
333 cross_drawable_->update_vertex_buffer(points);
334 cross_drawable_->set_visible(true);
335 }
336 } else {
337 if (cross_drawable_)
338 cross_drawable_->set_visible(false);
339 }
340
341 update();
342 }
343
344 return false;
345}
346
347
348vec3 TutorialRealCamera::camera_pos(
const mat3 &R,
const vec3 &t) {
350}
351
352
353vec3 TutorialRealCamera::pixel_to_ray(
int image_x,
int image_y,
float fx,
float fy,
float skew,
float cx,
float cy,
354 const mat3& R,
const vec3& t,
bool convert) {
356 0, fy, cy,
357 0, 0, 1);
358
359
360 vec3 P =
inverse(K) *
vec3(
static_cast<float>(image_x),
static_cast<float>(image_y), 1);
361 if (convert) {
364 P.y *= -1;
365 P.z *= -1;
366 }
367
368
370
371 return P - camera_pos(R, t);
372}
373
374
376 float fx, float fy, float skew, float cx, float cy,
379 0, fy, cy,
380 0, 0, 1);
386
387 if (convert) {
391 flip(1, 1) = -1;
392 flip(2, 2) = -1;
393 Rt = flip * Rt;
394 }
395
397 q /= q.z;
398
399 return vec2(q.x, q.y);
400}
401
402
A perspective or orthographic camera.
Definition camera.h:113
void setOrientation(const quat &q) const
Set the orientation of the camera.
float sceneRadius() const
Returns the radius of the scene observed by the Camera.
Definition camera.h:565
void setFieldOfView(float fov)
Set the field of view of the camera.
void set_from_calibration(float fx, float fy, float skew, float cx, float cy, const mat3 &R, const vec3 &t, bool convert=true)
Defines the position(), orientation() and fieldOfView() of the camera from calibrated camera intrinsi...
float fieldOfView() const
Returns the vertical field of view of the camera (in radians).
Definition camera.h:376
void setPosition(const vec3 &pos) const
Set the position of the camera.
ManipulatedCameraFrame * frame() const
Returns the ManipulatedFrame attached to the Camera.
Definition camera.h:623
mat4 worldMatrix() const
Returns the world transformation matrix of the Frame.
FT & x_min()
Returns the minimum x-coordinate.
Definition rect.h:79
FT height() const
Returns the height of the rectangle.
Definition rect.h:146
FT width() const
Returns the width of the rectangle.
Definition rect.h:141
FT & x_max()
Returns the maximum x-coordinate.
Definition rect.h:89
FT & y_min()
Returns the minimum y-coordinate.
Definition rect.h:84
FT & y_max()
Returns the maximum y-coordinate.
Definition rect.h:94
The drawable for rendering a set of line segments, e.g., edges of a mesh, vector fields.
Definition drawable_lines.h:40
@ CYLINDER
The lines will be drawn as cylinders.
Definition drawable_lines.h:60
Vec< N, T > col(size_t col) const
Returns the specified column as a vector.
Definition mat.h:723
void set_col(size_t col, const Vec< vN, T > &v)
Sets the specified column from a vector.
Definition mat.h:746
static ShaderProgram * create_program_from_files(const std::string &file_base_name, const std::vector< ShaderProgram::Attribute > &attributes=std::vector< ShaderProgram::Attribute >(), const std::vector< std::string > &outputs=std::vector< std::string >(), bool geom_shader=false)
Create a shader program from shader source files specified by the shader file's base name.
Definition shader_manager.cpp:49
static ShaderProgram * get_program(const std::string &shader_name)
Get the shader program if it exists and is working.
Definition shader_manager.cpp:41
OpenGL Shader Compilation.
Definition shader_program.h:75
void bind() const
Start using the program.
Definition shader_program.cpp:678
ShaderProgram * set_uniform(const std::string &name, const void *value)
Set the uniform to value.
Definition shader_program.cpp:436
void release() const
End using the program.
Definition shader_program.cpp:689
@ COLOR
Color.
Definition shader_program.h:80
@ POSITION
Position.
Definition shader_program.h:79
std::pair< AttribType, std::string > Attribute
Attribute: a pair of attribute type and attribute name.
Definition shader_program.h:85
static Texture * request(const std::string &image_file, Texture::WrapMode wrap=Texture::CLAMP_TO_EDGE, Texture::FilterMode filter=Texture::LINEAR)
Request a texture from the image file.
Definition texture_manager.cpp:40
bool is_file(const std::string &path)
Tests if 'path' is an existing file.
std::string directory()
Returns the resource directory (containing color maps, shaders, textures, fonts, etc....
void draw_quad_filled(const Rect &rect, const vec4 &color, int width, int height, float depth)
Draws a solid quad defined in the screen space.
Definition shape.cpp:90
void create_camera(std::vector< vec3 > &points, float width, float fov, float hw_ratio)
Generates data (points) for representing a camera in the 3D world as a set of lines.
Definition shape.cpp:985
void draw_quad_wire(const Rect &rect, const vec4 &color, int width, int height, float depth)
Draws a wire quad defined in the screen space.
Definition shape.cpp:42
std::string to_string(int v, int width, char fill)
Converts an integer value to a string of a desired length.
Definition string.cpp:127
Mat< M, N, T > transpose(const Mat< N, M, T > &m)
Transposes a matrix.
Definition mat.h:1120
Quat< float > quat
A quaternion of float type.
Definition types.h:85
Mat< N, N, T > inverse(const Mat< N, N, T > &m)
Returns the inverse of an N x N (square) matrix.
Definition mat.h:1190
Mat4< float > mat4
A 4 by 4 matrix of float type.
Definition types.h:67
Vec< 4, float > vec4
A 4D point/vector of float type.
Definition types.h:46
Mat< 3, 4, float > mat34
A 3 by 4 matrix of float type.
Definition types.h:69