00001
00002 #ifndef vpgl_generic_camera_txx_
00003 #define vpgl_generic_camera_txx_
00004
00005
00006
00007 #include "vpgl_generic_camera.h"
00008 #include <vnl/vnl_numeric_traits.h>
00009 #include <vcl_cassert.h>
00010 #include <vcl_cmath.h>
00011 #include <vgl/vgl_distance.h>
00012 #include <vgl/vgl_closest_point.h>
00013 #include <vgl/vgl_intersection.h>
00014 #include <vgl/vgl_vector_2d.h>
00015 #include <vgl/vgl_point_2d.h>
00016 #include <vgl/vgl_plane_3d.h>
00017 #include <vcl_iostream.h>
00018
00019 template <class T>
00020 vpgl_generic_camera<T>::vpgl_generic_camera()
00021 {
00022
00023 }
00024
00025
00026 template <class T>
00027 vpgl_generic_camera<T>::
00028 vpgl_generic_camera( vbl_array_2d<vgl_ray_3d<T> > const& rays)
00029 {
00030 int nc = rays.cols(), nr = rays.rows();
00031 assert(nc>0&&nr>0);
00032
00033 double min_dist = vnl_numeric_traits<double>::maxval;
00034 double max_dist = 0.0;
00035 vgl_point_3d<T> datum(T(0), T(0), T(0));
00036 for (int v = 0; v<nr; ++v)
00037 for (int u = 0; u<nc; ++u) {
00038 vgl_point_3d<T> org = rays[v][u].origin();
00039 double d = vgl_distance(datum, org);
00040 if (d>max_dist) {
00041 max_dist = d;
00042 max_ray_origin_ = org;
00043 max_ray_direction_ = rays[v][u].direction();
00044 }
00045 if (d<min_dist) {
00046 min_dist = d;
00047 min_ray_origin_ = org;
00048 min_ray_direction_ = rays[v][u].direction();
00049 }
00050 }
00051
00052
00053 double dim = nc;
00054 if (nr<nc)
00055 dim = nr;
00056 double lv = vcl_log(dim)/vcl_log(2.0);
00057 n_levels_ = static_cast<int>(lv);
00058 if (dim/vcl_pow(2.0, static_cast<double>(n_levels_-1)) < 3.0) n_levels_--;
00059 if (n_levels_<=0) n_levels_ = 1;
00060 rays_.resize(n_levels_);
00061 nr_.resize(n_levels_);
00062 nc_.resize(n_levels_);
00063 rays_[0]=rays;
00064 nr_[0]=nr; nc_[0]=nc;
00065 int nrlv = nr/2, nclv = nc/2;
00066 for (int lev = 1; lev<n_levels_; ++lev) {
00067 rays_[lev].resize(nrlv, nclv);
00068 nr_[lev]=nrlv; nc_[lev]=nclv;
00069 for (int r = 0; r<nrlv; ++r)
00070 for (int c = 0; c<nclv; ++c)
00071 rays_[lev][r][c] = rays_[lev-1][2*r][2*c];
00072
00073 nrlv /= 2; nclv /= 2;
00074 }
00075 }
00076
00077
00078
00079
00080
00081 template <class T>
00082 void vpgl_generic_camera<T>::nearest_ray(int level,
00083 vgl_point_3d<T> const& p,
00084 int start_r, int end_r,
00085 int start_c, int end_c,
00086 int& nearest_r, int& nearest_c) const
00087 {
00088 assert(level>=0 && level<n_levels_);
00089 assert(start_r>=0 && end_r < nr_[level]);
00090 assert(start_c>=0 && end_c < nc_[level]);
00091 nearest_r = 0, nearest_c = 0;
00092 double min_d = vnl_numeric_traits<double>::maxval;
00093 for (int r = start_r; r<=end_r; ++r)
00094 for (int c = start_c; c<=end_c; ++c) {
00095 double d = vgl_distance(rays_[level][r][c], p);
00096 if (d<min_d) {
00097 min_d=d;
00098 nearest_r = r;
00099 nearest_c = c;
00100 }
00101 }
00102 }
00103
00104 template <class T>
00105 void vpgl_generic_camera<T>::
00106 nearest_ray_to_point(vgl_point_3d<T> const& p,
00107 int& nearest_r, int& nearest_c) const
00108 {
00109 int lev = n_levels_-1;
00110 int start_r = 0, end_r = nr_[lev];
00111 int start_c = 0, end_c = nc_[lev];
00112 for (; lev >= 0; --lev) {
00113 if (start_r<0) start_r = 0;
00114 if (start_c<0) start_c = 0;
00115 if (end_r>=nr_[lev]) end_r = nr_[lev]-1;
00116 if (end_c>=nc_[lev]) end_c = nc_[lev]-1;
00117 nearest_ray(lev, p, start_r, end_r, start_c, end_c,
00118 nearest_r, nearest_c);
00119
00120 start_r = 2*nearest_r-1; start_c = 2*nearest_c-1;
00121 end_r = start_r + 2; end_c = start_c +2;
00122
00123 if (lev ==1&&nr_[0]%2!=0) end_r++;
00124 if (lev ==1&&nc_[0]%2!=0) end_c++;
00125 }
00126 }
00127
00128 template <class T>
00129 void vpgl_generic_camera<T>::
00130 refine_ray_at_point(int nearest_c, int nearest_r,
00131 vgl_point_3d<T> const& p,
00132 vgl_ray_3d<T>& ray) const
00133 {
00134 T u = static_cast<T>(nearest_c), v = static_cast<T>(nearest_r);
00135 ray = this->ray(u, v);
00136 vgl_point_3d<T> cp = vgl_closest_point(p, ray);
00137 vgl_vector_3d<T> t = p-cp;
00138 vgl_point_3d<T> org = ray.origin();
00139 org += t;
00140 ray.set(org, ray.direction());
00141 }
00142
00143
00144 template <class T>
00145 vgl_ray_3d<T> vpgl_generic_camera<T>::
00146 ray(vgl_point_3d<T> const& p) const
00147 {
00148 int nearest_c = -1, nearest_r = -1;
00149 this->nearest_ray_to_point(p, nearest_r, nearest_c);
00150 vgl_ray_3d<T> r;
00151 this->refine_ray_at_point(nearest_c, nearest_r, p, r);
00152 return r;
00153 }
00154
00155
00156
00157
00158
00159 template <class T>
00160 void vpgl_generic_camera<T>::
00161 refine_projection(int nearest_c, int nearest_r, vgl_point_3d<T> const& p,
00162 T& u, T& v) const
00163 {
00164
00165 vgl_ray_3d<T> nr = rays_[0][nearest_r][nearest_c];
00166
00167
00168 vgl_plane_3d<T> pl(-nr.direction(), p);
00169 bool valid_inter = true;
00170
00171 vcl_vector<vgl_point_3d<T> > inter_pts;
00172 vcl_vector<vgl_point_2d<T> > img_pts;
00173 vgl_point_3d<T> ipt;
00174 valid_inter = vgl_intersection(nr, pl, ipt);
00175 inter_pts.push_back(ipt);
00176
00177
00178 img_pts.push_back(vgl_point_2d<T>(0.0, 0.0));
00179 if (nearest_r>0) {
00180 vgl_ray_3d<T> r = rays_[0][nearest_r-1][nearest_c];
00181 valid_inter = vgl_intersection(r, pl, ipt);
00182 inter_pts.push_back(ipt);
00183 img_pts.push_back(vgl_point_2d<T>(0.0, -1.0));
00184 }
00185 if (nearest_c>0) {
00186 vgl_ray_3d<T> r = rays_[0][nearest_r][nearest_c-1];
00187 valid_inter = vgl_intersection(r, pl, ipt);
00188 inter_pts.push_back(ipt);
00189 img_pts.push_back(vgl_point_2d<T>(-1.0, 0.0));
00190 }
00191 int nrght = static_cast<int>(cols())-1;
00192 if (nearest_c<nrght) {
00193 vgl_ray_3d<T> r = rays_[0][nearest_r][nearest_c+1];
00194 valid_inter = vgl_intersection(r, pl, ipt);
00195 inter_pts.push_back(ipt);
00196 img_pts.push_back(vgl_point_2d<T>(1.0, 0.0));
00197 }
00198 int nbl = static_cast<int>(rows())-1;
00199 if (nearest_r<nbl) {
00200 vgl_ray_3d<T> r = rays_[0][nearest_r+1][nearest_c];
00201 valid_inter = vgl_intersection(r, pl, ipt);
00202 inter_pts.push_back(ipt);
00203 img_pts.push_back(vgl_point_2d<T>(0.0, 1.0));
00204 }
00205
00206 if (!valid_inter||inter_pts.size()<3) {
00207 u = static_cast<T>(nearest_c);
00208 v = static_cast<T>(nearest_r);
00209 return;
00210 }
00211
00212 vgl_point_3d<T> p0 = inter_pts[0];
00213
00214 vgl_vector_3d<T> v0 = inter_pts[1]- p0;
00215 vgl_vector_3d<T> v1 = inter_pts[2]- p0;
00216 vgl_vector_3d<T> vp = p-p0;
00217
00218 T x0 = dot_product(v0, vp), x1 = dot_product(v1, vp);
00219
00220
00221 vgl_point_2d<T> ip0 = img_pts[0];
00222 vgl_vector_2d<T> iv0 = img_pts[1]-ip0;
00223 vgl_vector_2d<T> iv1 = img_pts[2]-ip0;
00224 vgl_vector_2d<T> del = x0*iv0 + x1*iv1;
00225 u = nearest_c + del.x();
00226 v = nearest_r + del.y();
00227 }
00228
00229
00230 template <class T>
00231 void vpgl_generic_camera<T>::project(const T x, const T y, const T z,
00232 T& u, T& v) const
00233 {
00234 vgl_point_3d<T> p(x, y, z);
00235 int nearest_c=-1, nearest_r=-1;
00236 this->nearest_ray_to_point(p, nearest_r, nearest_c);
00237
00238 this->refine_projection(nearest_c, nearest_r, p, u, v);
00239 }
00240
00241
00242 template <class T>
00243 vgl_ray_3d<T> vpgl_generic_camera<T>::ray(const T u, const T v) const
00244 {
00245 double du = static_cast<double>(u);
00246 double dv = static_cast<double>(v);
00247 assert(du>=0.0&&dv>=0.0);
00248 int iu = static_cast<int>(du);
00249 int iv = static_cast<int>(dv);
00250 assert(iu<static_cast<int>(cols()) && iv<static_cast<int>(rows()));
00251
00252 if ((du-iu) == 0.0 && (dv-iv) == 0.0)
00253 return rays_[0][iv][iu];
00254
00255
00256 vcl_vector<double> dist;
00257 vcl_vector<vgl_ray_3d<T> > nrays;
00258
00259 if (iv>0) {
00260 vgl_ray_3d<T> ru = rays_[0][iv-1][iu];
00261 nrays.push_back(ru);
00262 double d = vcl_sqrt((iv-1-dv)*(iv-1-dv) + (iu-du)*(iu-du));
00263 if (d==0.0)
00264 return ru;
00265 dist.push_back(1.0/d);
00266 }
00267
00268 if (iu>0) {
00269 vgl_ray_3d<T> rl = rays_[0][iv][iu-1];
00270 nrays.push_back(rl);
00271 double d = vcl_sqrt((iv-dv)*(iv-dv) + (iu-1-du)*(iu-1-du));
00272 if (d==0.0)
00273 return rl;
00274 dist.push_back(1.0/d);
00275 }
00276
00277 int nrght = static_cast<int>(cols())-1;
00278 if (iu<nrght) {
00279 vgl_ray_3d<T> rr = rays_[0][iv][iu+1];
00280 nrays.push_back(rr);
00281 double d = vcl_sqrt((iv-dv)*(iv-dv) + (iu+1-du)*(iu+1-du));
00282 if (d==0.0)
00283 return rr;
00284 dist.push_back(1.0/d);
00285 }
00286
00287 int nbl = static_cast<int>(rows())-1;
00288 if (iv<nbl) {
00289 vgl_ray_3d<T> rd = rays_[0][iv+1][iu];
00290 nrays.push_back(rd);
00291 double d = vcl_sqrt((iv+1-dv)*(iv+1-dv) + (iu-du)*(iu-du));
00292 if (d==0.0)
00293 return rd;
00294 dist.push_back(1.0/d);
00295 }
00296
00297 double ox = 0.0, oy = 0.0, oz = 0.0, dx = 0.0, dy = 0.0, dz = 0.0;
00298 double sumw = 0.0;
00299 for (unsigned i = 0; i<nrays.size(); ++i) {
00300 vgl_ray_3d<T> r = nrays[i];
00301 vgl_point_3d<T> org = r.origin();
00302 vgl_vector_3d<T> dir = r.direction();
00303 double w = dist[i];
00304 sumw += w;
00305 ox += w*org.x(); oy += w*org.y(); oz += w*org.z();
00306 dx += w*dir.x(); dy += w*dir.y(); dz += w*dir.z();
00307 }
00308 ox /= sumw; oy /= sumw; oz /= sumw;
00309 dx /= sumw; dy /= sumw; dz /= sumw;
00310 vgl_point_3d<T> avg_org(static_cast<T>(ox),
00311 static_cast<T>(oy),
00312 static_cast<T>(oz));
00313 vgl_vector_3d<T> avg_dir(static_cast<T>(dx),
00314 static_cast<T>(dy),
00315 static_cast<T>(dz));
00316 return vgl_ray_3d<T>(avg_org, avg_dir);
00317 }
00318
00319
00320 template <class T>
00321 void vpgl_generic_camera<T>::print_orig(int level)
00322 {
00323 for (int r = 0; r<nr_[level]; ++r) {
00324 for (int c = 0; c<nc_[level]; ++c) {
00325 vgl_point_3d<T> o = rays_[level][r][c].origin();
00326 vcl_cout << '(' << o.x() << ' ' << o.y() << ") ";
00327 }
00328 vcl_cout << '\n';
00329 }
00330 }
00331
00332 template <class T>
00333 void vpgl_generic_camera<T>::print_to_vrml(int level, vcl_ostream& os)
00334 {
00335 for (int r = 0; r<nr_[level]; ++r) {
00336 for (int c = 0; c<nc_[level]; ++c) {
00337 vgl_point_3d<T> o = rays_[level][r][c].origin();
00338 os<< "Transform {\n"
00339 << "translation " << o.x() << ' ' << o.y() << ' '
00340 << ' ' << o.z() << '\n'
00341 << "children [\n"
00342 << "Shape {\n"
00343 << " appearance DEF A1 Appearance {\n"
00344 << " material Material\n"
00345 << " {\n"
00346 << " diffuseColor " << 1 << ' ' << 0 << ' ' << 0 << '\n'
00347 << " emissiveColor " << .3 << ' ' << 0 << ' ' << 0 << '\n'
00348 << " }\n"
00349 << " }\n"
00350 << " geometry Sphere\n"
00351 << "{\n"
00352 << " radius " << 20 << '\n'
00353 << " }\n"
00354 << " }\n"
00355 << " ]\n"
00356 << "}\n";
00357 }
00358 }
00359 }
00360
00361
00362 #undef vpgl_GENERIC_CAMERA_INSTANTIATE
00363 #define vpgl_GENERIC_CAMERA_INSTANTIATE(T) \
00364 template class vpgl_generic_camera<T >
00365
00366
00367 #endif // vpgl_generic_camera_txx_