1 // This is brl/bpro/core/vpgl_pro/processes/bpgl_transform_perspective_cameras_process.cxx
2 #include <iostream>
3 #include <fstream>
4 #include <bprb/bprb_func_process.h>
5 //:
6 // \file
7 #include <brdb/brdb_value.h>
8 #include <brdb/brdb_selection.h>
9 #include <bprb/bprb_batch_process_manager.h>
10 #include <bprb/bprb_parameters.h>
11 #include <bprb/bprb_macros.h>
12
13 #include "vul/vul_file.h"
14 #include "vul/vul_file_iterator.h"
15 #include <vgl/algo/vgl_rotation_3d.h>
16
17 #include "vpgl/vpgl_perspective_camera.h"
18 #include <bpgl/algo/bpgl_transform_camera.h>
19
20 namespace bpgl_transform_perspective_cameras_process_globals
21 {
22 constexpr unsigned n_inputs_ = 3;
23 constexpr unsigned n_outputs_ = 0;
24 }
25
26 //: Init function
bpgl_transform_perspective_cameras_process_cons(bprb_func_process & pro)27 bool bpgl_transform_perspective_cameras_process_cons(bprb_func_process& pro)
28 {
29 using namespace bpgl_transform_perspective_cameras_process_globals;
30
31 //process takes 3 inputs
32 std::vector<std::string> input_types_(n_inputs_);
33 input_types_[0] = "vcl_string"; // transformation file
34 input_types_[1] = "vcl_string"; // Input cam dir
35 input_types_[2] = "vcl_string"; // Output cam dir
36
37 // process has 0 outputs
38 std::vector<std::string> output_types_(n_outputs_);
39
40 return pro.set_input_types(input_types_) &&
41 pro.set_output_types(output_types_);
42 }
43
44 //: Execute the process
bpgl_transform_perspective_cameras_process(bprb_func_process & pro)45 bool bpgl_transform_perspective_cameras_process(bprb_func_process& pro)
46 {
47 // Sanity check
48 if (!pro.verify_inputs()) {
49 std::cerr << "bpgl_transform_perspective_cameras_process: Invalid inputs\n";
50 return false;
51 }
52
53 // get the inputs
54 unsigned i=0;
55 std::string xform_file = pro.get_input<std::string>(i++);
56 std::string in_dir = pro.get_input<std::string>(i++);
57 std::string out_dir = pro.get_input<std::string>(i++);
58 std::cout<<"out_dir "<<out_dir<<std::endl;
59 // check if input directory exists
60 if (!vul_file::is_directory(in_dir.c_str()))
61 {
62 std::cout<<"Input Camera directory does not exist"<<std::endl;
63 return false;
64 }
65
66 // check if output directory exists
67 if (!vul_file::is_directory(out_dir.c_str()))
68 {
69 std::cout<<"Output Camera directory does not exist"<<std::endl;
70 return false;
71 }
72
73 // read the xform file
74 // * xaxis yaxis zaxis roation angle
75 // * tx ty tz
76 // * scale
77 std::ifstream ifile(xform_file.c_str());
78 if (!ifile)
79 {
80 std::cout<<"Cannot open Xform file"<<std::endl;
81 return false;
82 }
83
84 double xr,yr,zr;
85 double tx,ty,tz,scale;
86
87 ifile>>xr>>yr>>zr;
88 ifile>>tx>>ty>>tz;
89 ifile>>scale;
90 vnl_quaternion<double> q(xr,yr,zr);
91 vgl_rotation_3d<double> R(q);
92 vnl_vector_fixed<double, 3> t;
93 t[0] = tx; t[1] = ty; t[2] = tz;
94 // xform and save the xformed cams
95 std::string glob_in_dir = in_dir + "/*.txt";
96 for (vul_file_iterator fn = glob_in_dir.c_str(); fn; ++fn) {
97 std::string f = fn();
98 std::ifstream is(f.c_str());
99 vpgl_perspective_camera<double> cam;
100 is >> cam;
101 is.close();
102 std::string fname = vul_file::strip_directory(f.c_str());
103 vpgl_perspective_camera<double> tcam = bpgl_transform_camera::transform_perspective_camera(cam, R, t, scale);
104 std::string out_file = out_dir + "/"+ fname;
105 std::ofstream os(out_file.c_str());
106 os << tcam;
107 os.close();
108 }
109 return true;
110 }
111
112
113 //
114 // this process is a version of bwm_3d_site_transform.cxx
115 //
116 // input: pts0 and pts1
117 // compute similarity transformation that maps space of pt0 to space of pts1
118 //
119 // the input camera is in the coordinate system of pts0. The output camera
120 // is the camera in the coordinate system of pts1, that is,
121 //
122 // x1 = K[R0|t0](Hs Hs^-1) X1, where Hs is the similarity transform.
123 //
124 // Thus, the similarity transform is applied to the camera as,
125 // (s = scale)
126 // _ _ _ _
127 // |s 0 0 0|| |
128 // K[R' | t'] = K[R0|t0]|0 s 0 0|| Rs ts|
129 // |0 0 s 0|| |
130 // |0 0 0 1|| 0 0 0 1|
131 // - - - -
132 // It follows that R' = R0*Rs and t' = t0/s + R0*ts
133 //
134 //
135
136 #include <core/bbas_pro/bbas_1d_array_double.h>
137 #include <vpgl/algo/vpgl_ortho_procrustes.h>
138 #include <vgl/algo/vgl_h_matrix_3d.h>
139 #include "vgl/vgl_box_3d.h"
140
141 static vpgl_perspective_camera<double>
vpgl_transform_space_process_transform_camera(vpgl_perspective_camera<double> const & cam,vgl_rotation_3d<double> const & Rs,vnl_vector_fixed<double,3> const & ts,const double scale)142 vpgl_transform_space_process_transform_camera(vpgl_perspective_camera<double> const& cam,
143 vgl_rotation_3d<double> const& Rs,
144 vnl_vector_fixed<double, 3> const& ts,
145 const double scale)
146 {
147 vnl_matrix_fixed<double,3,3> Rms = Rs.as_matrix();
148 //Get input camera components
149 //note, the homogeneous calibration matrix is unaffected by the scale
150 const vpgl_calibration_matrix<double>& K = cam.get_calibration();
151 vnl_matrix_fixed<double, 3, 3> R = cam.get_rotation().as_matrix();
152 vgl_vector_3d<double> tv = cam.get_translation();
153 vnl_vector_fixed<double, 3> t(tv.x(), tv.y(), tv.z());
154 //compose rotations
155 vnl_matrix_fixed<double, 3, 3> Rt = R*Rms;
156 vgl_rotation_3d<double> Rtr(Rt);
157 //compute new translation
158 vnl_vector_fixed<double, 3> tt = (1.0/scale)*t + R*ts;
159 vgl_vector_3d<double> ttg(tt[0], tt[1], tt[2]);
160 //construct transformed camera
161 vpgl_perspective_camera<double> camt(K, Rtr, ttg);
162 return camt;
163 }
164
165 //: sets input and output types
vpgl_transform_space_process_cons(bprb_func_process & pro)166 bool vpgl_transform_space_process_cons(bprb_func_process& pro)
167 {
168 //inputs
169 std::vector<std::string> input_types_(8);
170 input_types_[0] = "bbas_1d_array_double_sptr"; // x values of pts0 (points in SPACE 0)
171 input_types_[1] = "bbas_1d_array_double_sptr"; // y values of pts0 (points in SPACE 0)
172 input_types_[2] = "bbas_1d_array_double_sptr"; // z values of pts0 (points in SPACE 0)
173 input_types_[3] = "bbas_1d_array_double_sptr"; // x values of pts1 (points in SPACE 1)
174 input_types_[4] = "bbas_1d_array_double_sptr"; // y values of pts1 (points in SPACE 1)
175 input_types_[5] = "bbas_1d_array_double_sptr"; // z values of pts1 (points in SPACE 1)
176 input_types_[6] = "vcl_string"; // path to input camera folder
177 input_types_[7] = "vcl_string"; // path to output camera folder
178
179 if (!pro.set_input_types(input_types_))
180 return false;
181 //output
182 std::vector<std::string> output_types_(2);
183 output_types_[0] = "bbas_1d_array_double_sptr"; // output 4 by 4 similarity matrix as a vector of size 16
184 // construct the matrix as follows
185 // 0 1 2 3
186 // 4 5 6 7
187 // 8 9 10 11
188 // 12 13 14 15
189 output_types_[1] = "double"; // also output scale as a double to scale other quantities appropriately if needed, e.g. the voxel_size if a new scene.xml is needed
190 return pro.set_output_types(output_types_);
191 }
192
vpgl_transform_space_process(bprb_func_process & pro)193 bool vpgl_transform_space_process(bprb_func_process& pro)
194 {
195 //check number of inputs
196 if (!pro.verify_inputs())
197 {
198 std::cout << pro.name() << " invalid inputs" << std::endl;
199 return false;
200 }
201
202 //get the inputs
203 bbas_1d_array_double_sptr pts0_xs = pro.get_input<bbas_1d_array_double_sptr>(0);
204 bbas_1d_array_double_sptr pts0_ys = pro.get_input<bbas_1d_array_double_sptr>(1);
205 bbas_1d_array_double_sptr pts0_zs = pro.get_input<bbas_1d_array_double_sptr>(2);
206 bbas_1d_array_double_sptr pts1_xs = pro.get_input<bbas_1d_array_double_sptr>(3);
207 bbas_1d_array_double_sptr pts1_ys = pro.get_input<bbas_1d_array_double_sptr>(4);
208 bbas_1d_array_double_sptr pts1_zs = pro.get_input<bbas_1d_array_double_sptr>(5);
209
210 std::string input_cam_path = pro.get_input<std::string>(6);
211 std::string output_cam_path = pro.get_input<std::string>(7);
212
213 std::cout << pts0_xs->data_array;
214
215 vnl_matrix<double> pts0, pts1;
216 auto n = (unsigned)(pts0_xs->data_array.size());
217
218 pts0.set_size(3,n);
219 pts1.set_size(3,n);
220 for (unsigned i = 0; i<n; ++i) {
221 pts0[0][i] = pts0_xs->data_array[i]; pts1[0][i] = pts1_xs->data_array[i];
222 pts0[1][i] = pts0_ys->data_array[i]; pts1[1][i] = pts1_ys->data_array[i];
223 pts0[2][i] = pts0_zs->data_array[i]; pts1[2][i] = pts1_zs->data_array[i];
224 }
225
226 // prepare the output matrix as an array
227 bbas_1d_array_double_sptr out = new bbas_1d_array_double(16);
228
229 // compute the similarity transformation
230 vpgl_ortho_procrustes op(pts0, pts1);
231 vgl_rotation_3d<double> R = op.R();
232 vnl_vector_fixed<double, 3> t = op.t();
233 double scale = op.s();
234 if (! op.compute_ok()) {
235 std::cerr << "Problems during similarity transformation computation! Check if there are enough number of points! Current number of points: " << n << ". Minimum required number of points is 3, suggested to use a minimum of 5!" << std::endl;
236 pro.set_output_val<bbas_1d_array_double_sptr>(0, out);
237 return false;
238 }
239
240 std::cout << "Copmuted similarity matrix! Ortho procrustes error " << std::sqrt(op.residual_mean_sq_error()) << std::endl;
241
242 // read each camera and save the output camera in the output folder
243 std::string in_dir = input_cam_path + "/*.txt";
244 for (vul_file_iterator fn = in_dir.c_str(); fn; ++fn) {
245 std::string f = fn();
246 std::ifstream is(f.c_str());
247 vpgl_perspective_camera<double> cam;
248 is >> cam;
249 is.close();
250 std::string fname = vul_file::strip_directory(f.c_str());
251 std::cout << fname << std::endl;
252 vpgl_perspective_camera<double> tcam =
253 vpgl_transform_space_process_transform_camera(cam, R, t, scale);
254 std::cout<<"CC : "<<tcam.camera_center()<<std::endl;
255 std::string out_dir = output_cam_path + "/";
256 std::string out_file = out_dir + fname;
257 std::ofstream os(out_file.c_str());
258 os << tcam;
259 os.close();
260 }
261
262 // prepare the output matrix, we need the matrix that takes a point in the space of pts0 to the space of pts1,
263 // this is actually the inverse of the transformation computed above!!
264 vnl_matrix_fixed<double, 4, 4> S(0.0), outM(0.0);
265 S[0][0] = S[1][1] = S[2][2] = 1.0/scale; S[3][3] = 1.0;
266 // inverse of t is a little more complicated
267 vnl_vector_fixed<double, 3> t_inverse = -R.inverse().as_matrix()*t;
268 vgl_h_matrix_3d<double> RotT(R.inverse().as_matrix(), t_inverse);
269 outM = RotT.get_matrix()*S;
270
271 // copy to the output array
272 out->data_array[0] = outM[0][0]; out->data_array[1] = outM[0][1]; out->data_array[2] = outM[0][2]; out->data_array[3] = outM[0][3];
273 out->data_array[4] = outM[1][0]; out->data_array[5] = outM[1][1]; out->data_array[6] = outM[1][2]; out->data_array[7] = outM[1][3];
274 out->data_array[8] = outM[2][0]; out->data_array[9] = outM[2][1]; out->data_array[10] = outM[2][2]; out->data_array[11] = outM[2][3];
275 out->data_array[12] = outM[3][0]; out->data_array[13] = outM[3][1]; out->data_array[14] = outM[3][2]; out->data_array[15] = outM[3][3];
276
277 pro.set_output_val<bbas_1d_array_double_sptr>(0, out);
278 pro.set_output_val<double>(1,1.0/scale);
279 return true;
280 }
281
282 // a process to take min and max points of a box in the space of pts0 then transform 8 corner points to the space of pts1
283 // in the transformed space, compute a new axis aligned bounding box and return its min and max points
284
285 //: sets input and output types
vpgl_transform_box_process_cons(bprb_func_process & pro)286 bool vpgl_transform_box_process_cons(bprb_func_process& pro)
287 {
288 //inputs
289 std::vector<std::string> input_types_(3);
290 input_types_[0] = "bbas_1d_array_double_sptr"; // min pt x y z values in SPACE 0
291 input_types_[1] = "bbas_1d_array_double_sptr"; // max pt x y z values in SPACE 0
292 input_types_[2] = "bbas_1d_array_double_sptr"; // input 4 by 4 similarity matrix as a vector of size 16
293 // construct the matrix as follows
294 // 0 1 2 3
295 // 4 5 6 7
296 // 8 9 10 11
297 // 12 13 14 15
298
299
300 if (!pro.set_input_types(input_types_))
301 return false;
302 //output
303 std::vector<std::string> output_types_(2);
304 output_types_[0] = "bbas_1d_array_double_sptr"; // min pt x y z of the bounding box in SPACE 1
305 output_types_[1] = "bbas_1d_array_double_sptr"; // max pt x y z of the bounding box in SPACE 1
306 return pro.set_output_types(output_types_);
307 }
308
vpgl_transform_box_process(bprb_func_process & pro)309 bool vpgl_transform_box_process(bprb_func_process& pro)
310 {
311 //check number of inputs
312 if (!pro.verify_inputs())
313 {
314 std::cout << pro.name() << " invalid inputs" << std::endl;
315 return false;
316 }
317
318 //get the inputs
319 bbas_1d_array_double_sptr min_pt_a = pro.get_input<bbas_1d_array_double_sptr>(0);
320 bbas_1d_array_double_sptr max_pt_a = pro.get_input<bbas_1d_array_double_sptr>(1);
321 bbas_1d_array_double_sptr matrix = pro.get_input<bbas_1d_array_double_sptr>(2);
322
323 // construct the similarity matrix
324 vnl_matrix_fixed<double, 4, 4> SM;
325 SM[0][0] = matrix->data_array[0]; SM[0][1] = matrix->data_array[1]; SM[0][2] = matrix->data_array[2]; SM[0][3] = matrix->data_array[3];
326 SM[1][0] = matrix->data_array[4]; SM[1][1] = matrix->data_array[5]; SM[1][2] = matrix->data_array[6]; SM[1][3] = matrix->data_array[7];
327 SM[2][0] = matrix->data_array[8]; SM[2][1] = matrix->data_array[9]; SM[2][2] = matrix->data_array[10]; SM[2][3] = matrix->data_array[11];
328 SM[3][0] = matrix->data_array[12]; SM[3][1] = matrix->data_array[13]; SM[3][2] = matrix->data_array[14]; SM[3][3] = matrix->data_array[15];
329
330 // create 8 corners of the input box
331 vgl_box_3d<double> box1, box2;
332 box1.add(vgl_point_3d<double>(min_pt_a->data_array[0], min_pt_a->data_array[1], min_pt_a->data_array[2]));
333 box1.add(vgl_point_3d<double>(max_pt_a->data_array[0], max_pt_a->data_array[1], max_pt_a->data_array[2]));
334 std::vector<vgl_point_3d<double> > vertices = box1.vertices();
335
336 // transform 8 corners of the box and add to the new box in the transformed space
337 for (auto & vertice : vertices) {
338 vnl_matrix_fixed<double, 4, 1> pt, new_pt;
339 pt[0][0] = vertice.x(); pt[1][0] = vertice.y(); pt[2][0] = vertice.z(); pt[3][0] = 1.0;
340 new_pt = SM*pt;
341 box2.add(vgl_point_3d<double>(new_pt[0][0]/new_pt[3][0], new_pt[1][0]/new_pt[3][0], new_pt[2][0]/new_pt[3][0]));
342 }
343 vgl_point_3d<double> out_min_pt = box2.min_point();
344 vgl_point_3d<double> out_max_pt = box2.max_point();
345
346 bbas_1d_array_double_sptr outmin = new bbas_1d_array_double(3), outmax = new bbas_1d_array_double(3);
347 outmin->data_array[0] = out_min_pt.x(); outmin->data_array[1] = out_min_pt.y(); outmin->data_array[2] = out_min_pt.z();
348 outmax->data_array[0] = out_max_pt.x(); outmax->data_array[1] = out_max_pt.y(); outmax->data_array[2] = out_max_pt.z();
349
350 pro.set_output_val<bbas_1d_array_double_sptr>(0, outmin);
351 pro.set_output_val<bbas_1d_array_double_sptr>(1, outmax);
352 return true;
353 }
354