1 // This is core/vpgl/vpgl_affine_camera.hxx
2 #ifndef vpgl_affine_camera_hxx_
3 #define vpgl_affine_camera_hxx_
4 //:
5 // \file
6
7 #include "vpgl_affine_camera.h"
8 #include <vnl/vnl_vector_fixed.h>
9 #include <vnl/vnl_matrix_fixed.h>
10 #include <vnl/vnl_cross.h>
11 #include <vnl/vnl_det.h>
12 #include <vnl/vnl_inverse.h>
13 #include <vgl/algo/vgl_rotation_3d.h>
14 #include <vgl/vgl_closest_point.h>
15 #include <vgl/vgl_tolerance.h>
16 #include <vgl/vgl_ray_3d.h>
17 #ifdef _MSC_VER
18 # include <vcl_msvc_warnings.h>
19 #endif
20
21 //-------------------------------------------
22 template <class T>
vpgl_affine_camera()23 vpgl_affine_camera<T>::vpgl_affine_camera()
24 {
25 vnl_vector_fixed<T, 4> row1((T)1, (T)0, (T)0, (T)0);
26 vnl_vector_fixed<T, 4> row2((T)0, (T)1, (T)0, (T)0);
27 set_rows(row1, row2);
28 view_distance_ = (T)0;
29 }
30
31
32 //-------------------------------------------
33 template <class T>
vpgl_affine_camera(const vnl_vector_fixed<T,4> & row1,const vnl_vector_fixed<T,4> & row2)34 vpgl_affine_camera<T>::vpgl_affine_camera( const vnl_vector_fixed<T,4>& row1,
35 const vnl_vector_fixed<T,4>& row2 )
36 {
37 set_rows( row1, row2 );
38 view_distance_ = (T)0;
39 }
40
41
42 //------------------------------------------
43 template <class T>
vpgl_affine_camera(const vnl_matrix_fixed<T,3,4> & camera_matrix)44 vpgl_affine_camera<T>::vpgl_affine_camera( const vnl_matrix_fixed<T,3,4>& camera_matrix )
45 {
46 set_matrix( camera_matrix );
47 view_distance_ = (T)0;
48 }
49
50 template <class T>
51 vpgl_affine_camera<T>::
vpgl_affine_camera(vgl_vector_3d<T> ray,vgl_vector_3d<T> up,vgl_point_3d<T> stare_pt,T u0,T v0,T su,T sv)52 vpgl_affine_camera(vgl_vector_3d<T> ray, vgl_vector_3d<T> up,
53 vgl_point_3d<T> stare_pt,
54 T u0, T v0, T su, T sv) {
55
56 vgl_vector_3d<T> uvec = normalized(up), rvec = normalized(ray);
57 vnl_matrix_fixed<T,3,3> R;
58 if (std::fabs(dot_product<T>(uvec,rvec)-T(1))<1e-5)
59 {
60 T r[] = { 1, 0, 0,
61 0, 1, 0,
62 0, 0, 1 };
63
64 R = vnl_matrix_fixed<T,3,3>(r);
65 }
66 else if (std::fabs(dot_product<T>(uvec,rvec)-T(-1))<1e-5)
67 {
68 T r[] = { 1, 0, 0,
69 0, 1, 0,
70 0, 0, -1 };
71
72 R = vnl_matrix_fixed<T,3,3>(r);
73 }
74 else
75 {
76 vgl_vector_3d<T> x = cross_product(-uvec,rvec);
77 vgl_vector_3d<T> y = cross_product(rvec,x);
78 normalize(x);
79 normalize(y);
80
81 T r[] = { x.x(), x.y(), x.z(),
82 y.x(), y.y(), y.z(),
83 rvec.x(), rvec.y(), rvec.z() };
84
85 R = vnl_matrix_fixed<T,3,3>(r);
86 }
87
88 //form affine camera
89 vnl_vector_fixed<T, 4> r0, r1;
90 for (unsigned i = 0; i<3; ++i) {
91 r0[i] = su*R[0][i];
92 r1[i] = sv*R[1][i];
93 }
94 r0[3]= 0.0; r1[3]= 0.0;
95 this->set_rows(r0, r1);
96 T u, v;
97 this->project(stare_pt.x(), stare_pt.y(), stare_pt.z(), u, v);
98 T tu = (u0-u);
99 T tv = (v0-v);
100 r0[3]=tu; r1[3]=tv;
101 this->set_rows(r0, r1);
102 view_distance_ = (T)0;
103 ray_dir_.set(rvec.x(), rvec.y(), rvec.z());
104 }
105
106
107 //------------------------------------------
108 template <class T>
set_rows(const vnl_vector_fixed<T,4> & row1,const vnl_vector_fixed<T,4> & row2)109 void vpgl_affine_camera<T>::set_rows(
110 const vnl_vector_fixed<T,4>& row1,
111 const vnl_vector_fixed<T,4>& row2 )
112 {
113 vnl_matrix_fixed<T,3,4> C( (T)0 );
114 for ( unsigned int i = 0; i < 4; ++i ) {
115 C(0,i) = row1(i);
116 C(1,i) = row2(i);
117 }
118 C(2,3) = (T)1;
119 vpgl_proj_camera<T>::set_matrix( C );
120
121 // camera center for affine ray direction r is given by
122 // r . (a00, a01, a02) = r. A0 = 0
123 // r . (a10, a11, a12) = r. A1 = 0
124 // so r is orthogonal to both A0 and A1
125 vnl_vector_fixed<T, 3> A0, A1, r;
126 for (size_t i = 0; i < 3; ++i) {
127 A0[i] = row1[i];
128 A1[i] = row2[i];
129 }
130 r = vnl_cross_3d<T>(A0, A1);
131 ray_dir_.set(r[0], r[1], r[2]);
132 ray_dir_ /= ray_dir_.length();
133 }
134
135 template <class T>
set_matrix(const vnl_matrix_fixed<T,3,4> & new_camera_matrix)136 bool vpgl_affine_camera<T>::set_matrix( const vnl_matrix_fixed<T,3,4>& new_camera_matrix )
137 {
138 T norm = new_camera_matrix(2,3);
139 if (norm == T(0)) {
140 std::cerr << "vpgl_affine_camera::set_matrix normalization failure" << std::endl;
141 return false;
142 }
143
144 vnl_vector_fixed<T, 4> row0, row1;
145 for (size_t i = 0; i < 4; ++i) {
146 row0[i] = new_camera_matrix[0][i] / norm;
147 row1[i] = new_camera_matrix[1][i] / norm;
148 }
149 this->set_rows(row0, row1);
150 return true;
151 }
152
153 template <class T>
set_matrix(const T * new_camera_matrix_p)154 bool vpgl_affine_camera<T>::set_matrix( const T* new_camera_matrix_p )
155 {
156 vnl_matrix_fixed<T,3,4> new_camera_matrix( new_camera_matrix_p );
157 return set_matrix( new_camera_matrix );
158 }
159
160 //: Find the 3d coordinates of the center of the camera. Will be an ideal point with the sense of the ray direction.
161 template <class T>
camera_center() const162 vgl_homg_point_3d<T> vpgl_affine_camera<T>::camera_center() const
163 {
164 vgl_homg_point_3d<T> temp(ray_dir_.x(), ray_dir_.y(), ray_dir_.z(), (T)0);
165 return temp;
166 }
167
168 //: Find the 3d ray that goes through the camera center and the provided image point.
169 template <class T>
170 vgl_homg_line_3d_2_points<T> vpgl_affine_camera<T>::
backproject(const vgl_homg_point_2d<T> & image_point) const171 backproject( const vgl_homg_point_2d<T>& image_point ) const
172 {
173 // use affine construction of ray to produce the line
174 vgl_ray_3d<T> r = this->backproject_ray(image_point);
175 vgl_point_3d<T> org = r.origin();
176 vgl_vector_3d<T> dir = r.direction();
177
178 // return line (degenerate if appropriate)
179 if(dir.length() == T(0))
180 return vgl_homg_line_3d_2_points<T>(vgl_homg_point_3d<T>(org),vgl_homg_point_3d<T>(org));
181 else
182 return vgl_homg_line_3d_2_points<T>(vgl_homg_point_3d<T>(org),vgl_homg_point_3d<T>(org+dir));
183 }
184
185 template <class T>
186 vgl_ray_3d<T> vpgl_affine_camera<T>::
backproject_ray(const vgl_homg_point_2d<T> & image_point) const187 backproject_ray( const vgl_homg_point_2d<T>& image_point ) const
188 {
189 // return degnerate ray on failure
190 if(image_point.ideal(vgl_tolerance<T>::position)){
191 std::cerr << "Backproject ray from ideal point - degenerate result" << std::endl;
192 vgl_point_3d<T> org = vgl_point_3d<T>(T(0), T(0), T(0));
193 return vgl_ray_3d<T>(org,org);
194 }
195
196 // ray direction is already known only have to get a point in the ray.
197 // form the A0, A1 vectors
198 vnl_matrix_fixed<T, 3, 4> P = this->get_matrix();
199 vnl_vector_fixed<T, 3> A0, A1;
200 for(size_t i = 0; i<3; ++i){
201 A0[i] = P[0][i];
202 A1[i] = P[1][i];
203 }
204 vnl_matrix_fixed<T, 2, 2> D(T(0)), Dinv;
205 D[0][0] = dot_product(A0, A0);
206 D[0][1] = dot_product(A0, A1);
207 D[1][0] = D[0][1];
208 D[1][1] = dot_product(A1, A1);
209 double det = vnl_det(D);
210
211 // check singular determinant
212 if (fabs(det) < T(2)*vgl_tolerance<T>::position) {
213 std::cerr << "Backproject ray singular determinant - degenerate result" << std::endl;
214 vgl_point_3d<T> org = vgl_point_3d<T>(T(0), T(0), T(0));
215 return vgl_ray_3d<T>(org,org);
216 }
217
218 Dinv = vnl_inverse(D);
219 vnl_vector_fixed<T, 2> uv;
220 uv[0] = image_point.x() / image_point.w();
221 uv[1] = image_point.y() / image_point.w();
222 vnl_vector_fixed<T, 2> UV, a;
223 UV[0] = uv[0]-P[0][3];
224 UV[1] = uv[1]-P[1][3];
225 a = Dinv*UV;
226 vnl_vector_fixed<T, 3> p;
227 p = a[0]*A0 + a[1]*A1;
228 vgl_point_3d<T> org(p[0], p[1], p[2]);
229
230 // intersect ray with principal plane (specified by "view_distance")
231 // to obtain ray origin on the plane
232 if(view_distance_ == T(0)) {
233 return vgl_ray_3d<T>(org, ray_dir_);
234 } else {
235 T md = -view_distance_;
236 vgl_point_3d<T> pl_org = org + md*ray_dir_;
237 return vgl_ray_3d<T>(pl_org, ray_dir_);
238 }
239 }
240
clone() const241 template <class T> vpgl_affine_camera<T> *vpgl_affine_camera<T>::clone() const {
242 return new vpgl_affine_camera<T>(*this);
243 }
244
245 //: Find the world plane parallel to the image plane intersecting the camera center.
246 template <class T>
247 vgl_homg_plane_3d<T> vpgl_affine_camera<T>::
principal_plane() const248 principal_plane() const
249 {
250 //note that d = view_distance_ not -view_distance_,
251 //since dir points towards the origin
252 vgl_homg_plane_3d<T> ret(ray_dir_.x(), ray_dir_.y(),
253 ray_dir_.z(), view_distance_);
254 return ret;
255 }
256
257 //: flip the ray direction so that dot product with look_dir is positive
258 template <class T>
orient_ray_direction(vgl_vector_3d<T> const & look_dir)259 void vpgl_affine_camera<T>::orient_ray_direction(vgl_vector_3d<T> const& look_dir)
260 {
261 if (dot_product(look_dir, ray_dir_) < 0 ) {
262 ray_dir_ = -ray_dir_;
263 }
264 }
265
266 //: Write vpgl_affine_camera to stream
267 template <class Type>
operator <<(std::ostream & s,vpgl_affine_camera<Type> const & c)268 std::ostream& operator<<(std::ostream& s,
269 vpgl_affine_camera<Type> const& c)
270 {
271 s << c.get_matrix() << '\n';
272 return s;
273 }
274
275 //: Read camera from stream
276 template <class Type>
operator >>(std::istream & s,vpgl_affine_camera<Type> & c)277 std::istream& operator >>(std::istream& s,
278 vpgl_affine_camera<Type>& c)
279 {
280 vnl_matrix_fixed<Type, 3, 4> P;
281 s >> P;
282 c = vpgl_affine_camera<Type>(P);
283 return s ;
284 }
285
286 // the homography that transforms the camera to [I2x2|02x2]
287 // [ 01x3 |1]
288 //
289 // Note that A = [I2x2|02x2] H, where H4x4 = [ A_3x4 ]
290 // [ 01x3 |1] [ 01x3 |1]
291 //
292 // thus, canonical_h = H^-1
293 //
294 template <class T>
get_canonical_h(const vpgl_affine_camera<T> & camera)295 vgl_h_matrix_3d<T> get_canonical_h(const vpgl_affine_camera<T>& camera ){
296
297 vnl_matrix_fixed<T, 3,4> A = camera.get_matrix();
298 vnl_svd<T> temp(A.as_ref());
299 vnl_matrix_fixed<T, 4,3> Ainv = temp.pinverse();
300 vnl_matrix_fixed<T, 4, 4> Hinv(0.0), Hp(0.0);
301 for(size_t r = 0; r<4; ++r){
302 Hp[r][r] = T(1);
303 for(size_t c = 0; c<3; ++c){
304 Hinv[r][c] = Ainv[r][c];
305 }
306 }
307 Hinv[3][3]=T(1); Hp[0][3]=-A[0][3]; Hp[1][3]=-A[1][3];//remove 4th column (translation)
308 vgl_h_matrix_3d<T> ret(Hinv*Hp);
309 return ret;
310 }
311
312 template <class T>
premultiply_a(const vpgl_affine_camera<T> & in_camera,const vnl_matrix_fixed<T,3,3> & transform)313 vpgl_affine_camera<T> premultiply_a( const vpgl_affine_camera<T>& in_camera,
314 const vnl_matrix_fixed<T, 3, 3>& transform ){
315 return vpgl_affine_camera<T>(transform*in_camera.get_matrix());
316 }
317
318 template <class T>
postmultiply_a(const vpgl_affine_camera<T> & in_camera,const vnl_matrix_fixed<T,4,4> & transform)319 vpgl_affine_camera<T> postmultiply_a( const vpgl_affine_camera<T>& in_camera,
320 const vnl_matrix_fixed<T,4,4>& transform ){
321 return vpgl_affine_camera<T>(in_camera.get_matrix()*transform);
322 }
323
324 template <class T>
postmultiply_a(const vpgl_affine_camera<T> & in_camera,const vnl_vector_fixed<T,3> & translation)325 vpgl_affine_camera<T> postmultiply_a( const vpgl_affine_camera<T>& in_camera,
326 const vnl_vector_fixed<T,3>& translation ){
327 const vnl_matrix_fixed<T, 3, 4> m = in_camera.get_matrix();
328 vnl_matrix_fixed<T, 3, 4> tm = m;
329 vnl_vector_fixed<T, 4> r0 = m.get_row(0), r1 = m.get_row(1);
330 vnl_vector_fixed<T, 4> t;
331 for(size_t c = 0; c<3; ++c) t[c] = translation[c]; t[3] = T(1);
332 T dp0 = dot_product(r0, t); tm[0][3] = dp0;
333 T dp1 = dot_product(r1, t); tm[1][3] = dp1;
334 return vpgl_affine_camera<T>(tm);
335 }
336
337 // Code for easy instantiation.
338 #undef vpgl_AFFINE_CAMERA_INSTANTIATE
339 #define vpgl_AFFINE_CAMERA_INSTANTIATE(T) \
340 template class vpgl_affine_camera<T >; \
341 template std::ostream& operator<<(std::ostream&, const vpgl_affine_camera<T >&); \
342 template std::istream& operator>>(std::istream&, vpgl_affine_camera<T >&); \
343 template vgl_h_matrix_3d<T> get_canonical_h(const vpgl_affine_camera<T>&); \
344 template vpgl_affine_camera<T> premultiply_a( const vpgl_affine_camera<T>&, const vnl_matrix_fixed<T,3,3>&); \
345 template vpgl_affine_camera<T> premultiply_a( const vpgl_affine_camera<T>&, const vgl_h_matrix_2d<T>&); \
346 template vpgl_affine_camera<T> postmultiply_a( const vpgl_affine_camera<T>&, const vnl_matrix_fixed<T,4,4>&); \
347 template vpgl_affine_camera<T> postmultiply_a( const vpgl_affine_camera<T>&, const vgl_h_matrix_3d<T>&); \
348 template vpgl_affine_camera<T> postmultiply_a( const vpgl_affine_camera<T>&, const vnl_vector_fixed<T,3>&); \
349 template vpgl_affine_camera<T> postmultiply_a( const vpgl_affine_camera<T>&, const vgl_vector_3d<T>&)
350
351
352 #endif // vpgl_affine_camera_hxx_
353