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>
50const float scale = 0.3f;
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)
58 , cameras_drawable_(nullptr)
59 , ray_drawable_(nullptr)
60 , cross_drawable_(nullptr)
63 if (add_model(cloud_file)) {
64 auto drawable = current_model()->renderer()->get_points_drawable(
"vertices");
65 drawable->set_point_size(5.0f);
68 if (read_bundler_file(bundler_file))
69 update_cameras_drawable(
true);
71 LOG(ERROR) <<
"failed to load bundler file";
73 camera()->setUpVector(
vec3(0, 1, 0));
74 camera()->setViewDirection(
vec3(0, 0, -1));
75 camera_->showEntireScene();
78 LOG(ERROR) <<
"failed to load point cloud";
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";
87bool TutorialRealCamera::key_press_event(
int key,
int modifiers) {
89 ray_drawable_->set_visible(
false);
91 cross_drawable_->set_visible(
false);
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_];
103 resize(
static_cast<int>(
static_cast<float>(c.w) * scale),
static_cast<int>(
static_cast<float>(c.h) * scale));
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_];
117 resize(
static_cast<int>(
static_cast<float>(c.w) * scale),
static_cast<int>(
static_cast<float>(c.h) * scale));
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_];
131 resize(
static_cast<int>(
static_cast<float>(c.w) * scale),
static_cast<int>(
static_cast<float>(c.h) * scale));
136 else if (key == KEY_H) {
137 if (cameras_drawable_) {
138 cameras_drawable_->set_visible(!cameras_drawable_->is_visible());
144 return Viewer::key_press_event(key, modifiers);
148void TutorialRealCamera::load_image() {
149 const std::string image_file = resource::directory() +
"/data/fountain/images/" + string::to_string(current_view_, 4,
'0') +
".jpg";
150 if (file_system::is_file(image_file)) {
151 texture_ = TextureManager::request(image_file);
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;
163 const CameraPara& cam = views_[view_index];
170 const float proj11 = 2.0f * cam.fy /
static_cast<float>(cam.h);
171 const float fov = 2.0f * std::atan(1.0f / proj11);
176 cam.fx, cam.fy, 0.0f,
187void TutorialRealCamera::update_cameras_drawable(
bool ground_truth)
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);
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;
201 shape::create_camera(points, c.
sceneRadius() * 0.03f, c.
fieldOfView(),
static_cast<float>(views_[i].h)/
static_cast<float>(views_[i].w));
203 for (
auto& p : points)
204 vertices.push_back(m * p);
207 cameras_drawable_->update_vertex_buffer(vertices);
211Rect TutorialRealCamera::calculate_image_rect()
const {
212 if (texture_ ==
nullptr) {
213 LOG_N_TIMES(3, ERROR) <<
"image not shown";
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);
226 tex_w =
static_cast<int>(
static_cast<float>(width()) * scale);
227 tex_h =
static_cast<int>(
static_cast<float>(tex_w) / image_as);
231 const int y = 120.0f;
232 return Rect(x, x +
static_cast<float>(tex_w), y, y +
static_cast<float>(tex_h));
236void TutorialRealCamera::post_draw() {
237 if (texture_ ==
nullptr)
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());
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());
246 shape::draw_quad_filled(quad, texture_->id(), w, h, -0.9f);
247 shape::draw_quad_wire(quad,
vec4(1.0f, 0.0f, 0.0f, 1.0f), w, h, -0.99f);
249 if (cross_drawable_ && cross_drawable_->is_visible()) {
250 ShaderProgram *program = ShaderManager::get_program(
"lines/lines_plain_color");
252 std::vector<ShaderProgram::Attribute> attributes;
255 program = ShaderManager::create_program_from_files(
"lines/lines_plain_color", attributes);
260 const mat4 &proj = transform::ortho(0.0f,
static_cast<float>(width()),
static_cast<float>(height()), 0.0f,
262 glDisable(GL_DEPTH_TEST);
267 cross_drawable_->gl_draw();
269 glEnable(GL_DEPTH_TEST);
276bool TutorialRealCamera::mouse_free_move_event(
int x,
int y,
int dx,
int dy,
int modifiers) {
281 if (current_view_ < 0 || current_view_ >= views_.size()) {
282 std::cerr <<
"Error: invalid view index (" << current_view_ <<
")" << std::endl;
286 const CameraPara &cam = views_[current_view_];
287 const Rect image_rect = calculate_image_rect();
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);
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);
307 ray_drawable_->set_visible(
false);
310 const vec3 p = point_under_pixel(x, y, found);
312 const vec2 q = point_to_pixel(p, cam.fx, cam.fy, 0, cam.cx, cam.cy, cam.R, cam.t);
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);
324#if defined(__APPLE__)
325 const float size = 10;
327 const float size =
static_cast<float>(10 * dpi_scaling());
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)
333 cross_drawable_->update_vertex_buffer(points);
334 cross_drawable_->set_visible(
true);
338 cross_drawable_->set_visible(
false);
348vec3 TutorialRealCamera::camera_pos(
const mat3 &R,
const vec3 &t) {
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) {
360 vec3 P =
inverse(K) *
vec3(
static_cast<float>(image_x),
static_cast<float>(image_y), 1);
371 return P - camera_pos(R, t);
376 float fx,
float fy,
float skew,
float cx,
float cy,
399 return vec2(q.x, q.y);
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
@ CYLINDER
The lines will be drawn as cylinders.
Definition drawable_lines.h:60
Base class for matrix types.
Definition mat.h:64
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
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
std::pair< AttribType, std::string > Attribute
Attribute: a pair of attribute type and attribute name.
Definition shader_program.h:85
Mat< M, N, T > transpose(const Mat< N, M, T > &m)
Transposes a matrix.
Definition mat.h:1120
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