00001
00002 #include "strk_tracker.h"
00003
00004
00005 #include <vcl_cmath.h>
00006 #include <vcl_algorithm.h>
00007 #include <vul/vul_timer.h>
00008 #include <vnl/vnl_math.h>
00009 #include <vgl/vgl_polygon.h>
00010 #include <vgl/vgl_polygon_scan_iterator.h>
00011 #include <vil1/vil1_memory_image_of.h>
00012 #include <vtol/vtol_intensity_face.h>
00013 #include <vtol/vtol_vertex_2d.h>
00014 #include <brip/brip_vil1_float_ops.h>
00015
00016 strk_correlated_face::strk_correlated_face()
00017 {
00018 Ix_ = 0;
00019 Iy_ = 0;
00020 c_ = 0;
00021 f_ = 0;
00022 }
00023
00024 strk_correlated_face::~strk_correlated_face()
00025 {
00026 delete[] Ix_;
00027 delete[] Iy_;
00028 }
00029
00030 void strk_correlated_face::set_face(vtol_intensity_face_sptr const& f)
00031 {
00032 f_ = f;
00033 if (Ix_)
00034 delete[] Ix_;
00035 if (Iy_)
00036 delete[] Iy_;
00037 int n = f->Npix();
00038 Ix_ = new float[n];
00039 Iy_ = new float[n];
00040 }
00041
00042
00043 static bool corr_compare(strk_correlated_face* const f1,
00044 strk_correlated_face* const f2)
00045 {
00046 return f1->correlation() < f2->correlation();
00047 }
00048
00049
00050
00051
00052
00053
00054
00055
00056 strk_tracker::strk_tracker(strk_tracker_params& tp)
00057 : strk_tracker_params(tp)
00058 {
00059 hypothesized_samples_.clear();
00060 }
00061
00062
00063 strk_tracker::~strk_tracker()
00064 {
00065 for (vcl_vector<strk_correlated_face*>::iterator
00066 cit = hypothesized_samples_.begin();
00067 cit != hypothesized_samples_.end(); cit++)
00068 delete *cit;
00069 hypothesized_samples_.clear();
00070
00071 for (vcl_vector<strk_correlated_face*>::iterator
00072 cit = current_samples_.begin();
00073 cit != current_samples_.end(); cit++)
00074 delete *cit;
00075 current_samples_.clear();
00076 }
00077
00078 void strk_tracker::set_gradient(strk_correlated_face* cf,
00079 vil1_memory_image_of<float> const& Ix,
00080 vil1_memory_image_of<float> const& Iy)
00081 {
00082 if (!cf)
00083 return;
00084 vtol_intensity_face_sptr f = cf->face();
00085 int i = 0;
00086 for (f->reset(); f->next();i++)
00087 {
00088 int x = int(f->X()), y = int(f->Y());
00089 cf->set_Ix(i, Ix(x,y));
00090 cf->set_Iy(i, Iy(x,y));
00091 }
00092 }
00093
00094
00095
00096
00097 void strk_tracker::set_image_0(vil1_image& image)
00098 {
00099 if (!image)
00100 {
00101 vcl_cout <<"In strk_tracker::set_image_i(.) - null input\n";
00102 return;
00103 }
00104
00105 vil1_memory_image_of<float> flt=brip_vil1_float_ops::convert_to_float(image);
00106
00107 image_0_= brip_vil1_float_ops::gaussian(flt, sigma_);
00108
00109 int w = image_0_.width(), h = image_0_.height();
00110 Ix_0_.resize(w,h);
00111 Iy_0_.resize(w,h);
00112 brip_vil1_float_ops::gradient_3x3(image_0_, Ix_0_, Iy_0_);
00113 }
00114
00115
00116
00117
00118 void strk_tracker::set_image_i(vil1_image& image)
00119 {
00120 if (!image)
00121 {
00122 vcl_cout <<"In strk_tracker::set_image_i(.) - null input\n";
00123 return;
00124 }
00125
00126 vil1_memory_image_of<float> flt=brip_vil1_float_ops::convert_to_float(image);
00127
00128 image_i_ = brip_vil1_float_ops::gaussian(flt, sigma_);
00129 }
00130
00131
00132
00133 void strk_tracker::set_initial_model(vtol_face_2d_sptr const& face)
00134 {
00135 initial_model_ = face;
00136 }
00137
00138
00139
00140 void strk_tracker::fill_face(vtol_intensity_face_sptr const& face,
00141 vil1_memory_image_of<float> const& image)
00142 {
00143 if (!face)
00144 return;
00145 int width = image.width(), height = image.height();
00146 face->ResetPixelData();
00147 vgl_polygon<float> p;
00148 p.new_sheet();
00149 vcl_vector<vtol_vertex_sptr> verts;
00150 face->vertices(verts);
00151 for (vcl_vector<vtol_vertex_sptr>::iterator vit = verts.begin();
00152 vit != verts.end(); vit++)
00153 p.push_back(float((*vit)->cast_to_vertex_2d()->x()),
00154 float((*vit)->cast_to_vertex_2d()->y()));
00155 vgl_polygon_scan_iterator<float> psi(p, true);
00156
00157
00158 for (psi.reset(); psi.next(); )
00159 for (int x = psi.startx(); x<=psi.endx(); x++)
00160 {
00161 int y = psi.scany();
00162 if (x<0||x>=width||y<0||y>=height)
00163 continue;
00164
00165 unsigned short v = (unsigned short)image(x, y);
00166 face->IncrementMeans(float(x), float(y), v);
00167 }
00168 face->InitPixelArrays();
00169
00170 for (psi.reset(); psi.next();)
00171 for (int x = psi.startx(); x<=psi.endx(); x++)
00172 {
00173 int y = psi.scany();
00174 if (x<0||x>=width||y<0||y>=height)
00175 continue;
00176 unsigned short v = (unsigned short)image(x, y);
00177 face->InsertInPixelArrays(float(x), float(y), v);
00178 }
00179 }
00180
00181
00182
00183 void strk_tracker::init()
00184 {
00185 if (!image_0_)
00186 return;
00187 if (!initial_model_)
00188 return;
00189 vtol_intensity_face_sptr intf = new vtol_intensity_face(initial_model_);
00190 this->fill_face(intf, image_0_);
00191 strk_correlated_face* cf = new strk_correlated_face();
00192 cf->set_face(intf);
00193 this->set_gradient(cf, Ix_0_, Iy_0_);
00194 current_samples_.push_back(cf);
00195 }
00196
00197
00198
00199 vtol_intensity_face_sptr
00200 strk_tracker::transform_face(vtol_intensity_face_sptr const& face,
00201 double tx, double ty, double theta, double scale)
00202 {
00203 if (!face)
00204 return 0;
00205 double xo = face->Xo(), yo = face->Yo();
00206 double c = vcl_cos(theta), s = vcl_sin(theta);
00207
00208 int npix = face->Npix();
00209 float* X = new float[npix];
00210 float* Y = new float[npix];
00211 unsigned short* I = new unsigned short[npix];
00212 float const* Xj = face->Xj();
00213 float const* Yj = face->Yj();
00214 unsigned short const* Ij = face->Ij();
00215 for (int i=0; i<npix; i++)
00216 {
00217 double x = Xj[i], y = Yj[i];
00218 double xp =(x-xo)*scale, yp =(y-yo)*scale;
00219 X[i] = float(xp*c - yp*s + xo + tx);
00220 Y[i] = float(xp*s + yp*c + yo + ty);
00221 I[i] = Ij[i];
00222 }
00223 vcl_vector<vtol_vertex_sptr> verts, new_verts;
00224 face->vertices(verts);
00225 if (verts.size()<3)
00226 return 0;
00227
00228 for (vcl_vector<vtol_vertex_sptr>::iterator vit = verts.begin();
00229 vit != verts.end(); vit++)
00230 {
00231 vtol_vertex_2d_sptr v = (*vit)->cast_to_vertex_2d();
00232 if (!v)
00233 continue;
00234 double x = v->x(), y = v->y();
00235 double xp =(x-xo)*scale, yp =(y-yo)*scale;
00236 double new_x = xp*c - yp*s + xo + tx;
00237 double new_y = xp*s + yp*c + yo + ty;
00238 vtol_vertex_sptr new_v = new vtol_vertex_2d(new_x, new_y);
00239 new_verts.push_back(new_v);
00240 }
00241 vtol_face_2d_sptr f2d = new vtol_face_2d(new_verts);
00242 vtol_intensity_face_sptr new_int_face =
00243 new vtol_intensity_face(f2d, npix, X, Y, I);
00244 #ifdef DEBUG
00245 vcl_cout << "Transformed Face Centroid (" << new_int_face->Xo()<< ' '
00246 << new_int_face->Yo() << ")\n";
00247 #endif // DEBUG
00248
00249 delete[] X;
00250 delete[] Y;
00251 delete[] I;
00252 return new_int_face;
00253 }
00254
00255
00256
00257
00258 bool strk_tracker::compute_motion(strk_correlated_face* cf,
00259 double& tx, double& ty, double& theta,
00260 double& scale)
00261 {
00262 tx = 0; ty =0; theta =0;
00263 if (!cf)
00264 return false;
00265 int width = image_i_.width(), height = image_i_.height();
00266 vtol_intensity_face_sptr face = cf->face();
00267 if (!face)
00268 return false;
00269 int i = 0;
00270 double IxIx=0, IxIy = 0, IyIy =0;
00271 double bx = 0, by =0;
00272 double sn_th = 0, sd_th = 0, sn_sc = 0, sd_sc=0;
00273 double xo = face->Xo(), yo = face->Yo();
00274 for (face->reset(); face->next();)
00275 {
00276 int x = int(face->X()), y = int(face->Y());
00277 if (x<0||x>=width||y<0||y>=height)
00278 continue;
00279 float Ii = image_i_(x,y);
00280 float dI = Ii-face->I();
00281 float Ix = cf->Ix(i), Iy = cf->Iy(i);
00282 double Ith = (-Ix*(y-yo)+Iy*(x-xo));
00283 double Isc = (Ix*(x-xo)+Iy*(y-yo));
00284 IxIx += Ix*Ix;
00285 IxIy += Ix*Iy;
00286 IyIy += Iy*Iy;
00287 bx -= dI*Ix;
00288 by -= dI*Iy;
00289 sn_th += dI*Ith;
00290 sd_th += Ith*Ith;
00291 sn_sc += dI*Isc;
00292 sd_sc += Isc*Isc;
00293 i++;
00294 }
00295
00296
00297
00298 double det = IxIx*IyIy-IxIy*IxIy;
00299 if (vcl_fabs(det)<1e-06||sd_th<1e-06||sd_sc<1.e-06)
00300 return false;
00301
00302
00303
00304
00305
00306
00307 tx = ( IyIy*bx - IxIy*by)/det;
00308 ty = (-IxIy*bx + IxIx*by)/det;
00309 theta = -sn_th/sd_th;
00310 scale = 1.0 - sn_sc/sd_sc;
00311 return true;
00312 }
00313
00314 double strk_tracker::compute_gradient_angle(strk_correlated_face* cf)
00315 {
00316 if (!cf)
00317 return false;
00318 int width = image_i_.width(), height = image_i_.height();
00319 vtol_intensity_face_sptr face = cf->face();
00320 if (!face)
00321 return false;
00322 double IxIx=0, IxIy = 0, IyIy =0;
00323 for (face->reset(); face->next();)
00324 {
00325 int x = int(face->X()), y = int(face->Y());
00326 if (x<0||x>=width||y<0||y>=height)
00327 continue;
00328 float Ix = Ix_i_(x,y), Iy = Iy_i_(x,y);
00329 IxIx += Ix*Ix;
00330 IxIy += Ix*Iy;
00331 IyIy += Iy*Iy;
00332 }
00333 #ifdef DEBUG
00334 vcl_cout << " G = " << '\n' << IxIx << ' ' << IxIy << '\n'
00335 << IxIy << ' ' << IyIy << "\n\n";
00336 #endif // DEBUG
00337 double theta_rad = 0.5*vcl_atan2(2*IxIy,(IyIy-IxIx));
00338 double theta_deg = (180*theta_rad)/vnl_math::pi;
00339 return theta_deg;
00340 }
00341
00342
00343 double strk_tracker::compute_angle_motion(strk_correlated_face* cf)
00344 {
00345 if (!cf)
00346 return 0;
00347 int width = image_i_.width(), height = image_i_.height();
00348 double sn = 0, sd=0;
00349 int i = 0;
00350 vtol_intensity_face_sptr face = cf->face();
00351 double xo = face->Xo(), yo = face->Yo();
00352 for (face->reset(); face->next();)
00353 {
00354 int x = int(face->X()), y = int(face->Y());
00355 if (x<0||x>=width||y<0||y>=height)
00356 continue;
00357 float Ii = image_i_(x,y);
00358 float dI = Ii-face->I();
00359 float Ix = cf->Ix(i), Iy = cf->Iy(i);
00360 double Ith = (-Ix*(y-yo)+Iy*(x-xo));
00361 sn += dI*Ith;
00362 sd += Ith*Ith;
00363 }
00364 double theta = 180*sn/(sd*vnl_math::pi);
00365 return theta;
00366 }
00367
00368 bool strk_tracker::
00369 compute_scale_motion(strk_correlated_face* cf, double& sx, double& sy)
00370 {
00371 sx =1.0;
00372 sy =1.0;
00373 if (!cf)
00374 return false;
00375 int width = image_i_.width(), height = image_i_.height();
00376 double xxIxIx = 0, xyIxIy = 0, yyIyIy=0;
00377 double xdIIx = 0, ydIIy = 0;
00378 int i = 0;
00379 vtol_intensity_face_sptr face = cf->face();
00380 double xo = face->Xo(), yo = face->Yo();
00381 for (face->reset(); face->next();)
00382 {
00383 int x = int(face->X()), y = int(face->Y());
00384 if (x<0||x>=width||y<0||y>=height)
00385 continue;
00386 float Ii = image_i_(x,y);
00387 float dI = Ii-face->I();
00388 float Ix = cf->Ix(i), Iy = cf->Iy(i);
00389 float dx = float(x-xo), dy = float(y-yo);
00390 xxIxIx += dx*dx*Ix*Ix;
00391 xyIxIy += dx*dy*Ix*Iy;
00392 yyIyIy += dy*dy*Iy*Iy;
00393 xdIIx -= dx*dI*Ix;
00394 ydIIy -= dy*dI*Iy;
00395 }
00396 double det = xxIxIx*yyIyIy-xyIxIy*xyIxIy;
00397 if (det<1e-06)
00398 return false;
00399 sx = 1+(yyIyIy*xdIIx - xyIxIy*ydIIy)/det;
00400 sy = 1+(xxIxIx*ydIIy - xyIxIy*xdIIx)/det;
00401 return true;
00402 }
00403
00404 double strk_tracker::compute_correlation(strk_correlated_face* cf)
00405 {
00406 if (!cf)
00407 return 0;
00408 int width = image_i_.width(), height = image_i_.height();
00409 double c = 0;
00410 int i = 0;
00411 vtol_intensity_face_sptr face = cf->face();
00412 for (face->reset(); face->next();)
00413 {
00414 int x = int(face->X()), y = int(face->Y());
00415 if (x<0||x>=width||y<0||y>=height)
00416 continue;
00417 float Ii = image_i_(x,y);
00418 float dI = Ii-face->I();
00419 c += dI*dI;
00420 i++;
00421 }
00422 if (i)
00423 return c/=i;
00424 else
00425 return 1e6;
00426 }
00427
00428
00429
00430 void strk_tracker::correlate_face(strk_correlated_face* cf)
00431 {
00432 float corr_thresh = 100.f;
00433 double tx=0, ty=0, theta = 0, scale=1.0;
00434 double sx=0, sy=0;
00435 double sth =0, psc = 1.0;
00436 double c = vcl_sqrt(this->compute_correlation(cf));
00437 if (c>corr_thresh)
00438 {
00439 cf->set_correlation(float(c));
00440 return;
00441 }
00442
00443 if (!this->compute_motion(cf, tx, ty, theta, scale))
00444 {
00445 cf->set_correlation(1e6f);
00446 return;
00447 }
00448
00449 sx+=tx; sy+=ty;
00450 #ifdef DEBUG
00451 vcl_cout << "Initial corr("<< tx << ' ' << ty << ")= " << this->compute_correlation(cf)<< '\n';
00452 #endif // DEBUG
00453
00454 bool done = false;
00455 int max_iter = 3;
00456 double thresh = 0.1;
00457
00458 while ((!done)&&max_iter>0)
00459 {
00460 this->transform_sample_in_place(cf, tx, ty, theta, scale);
00461 if (!this->compute_motion(cf, tx, ty, theta, scale))
00462 {
00463 cf->set_correlation(1e6f);
00464 return;
00465 }
00466 if ((vcl_fabs(tx)<thresh)&&vcl_fabs(ty)<thresh&&vcl_fabs(theta)<0.01
00467 &&vcl_fabs(scale-1.0)<0.01)
00468 done=true;
00469 sx+=tx; sy+=ty;
00470 sth += theta;
00471 psc *=scale;
00472 max_iter--;
00473 }
00474 c = this->compute_correlation(cf);
00475 #ifdef DEBUG
00476 vcl_cout << "Final corr(" << sx << ' ' << sy << ' ' << sth << ' ' << psc
00477 << ") = " << vcl_sqrt(c) << '\n';
00478 #endif //DEBUG
00479 cf->set_correlation((float)vcl_sqrt(c));
00480 }
00481
00482
00483
00484 vtol_intensity_face_sptr
00485 strk_tracker::generate_sample(vtol_intensity_face_sptr const& seed)
00486 {
00487 float x = (2.f*search_radius_)*float(rand()/(RAND_MAX+1.f)) - search_radius_;
00488 float y = (2.f*search_radius_)*float(rand()/(RAND_MAX+1.f)) - search_radius_;
00489 float theta = (2.f*angle_range_)*float(rand()/(RAND_MAX+1.f)) - angle_range_;
00490 float s = (2.f*scale_range_)*float(rand()/(RAND_MAX+1.f)) - scale_range_;
00491 float scale = 1+s;
00492 return this->transform_face(seed, x, y, theta, scale);
00493 }
00494
00495
00496
00497 strk_correlated_face*
00498 strk_tracker::generate_cf_sample(strk_correlated_face* seed)
00499 {
00500 if (!seed)
00501 return 0;
00502 vtol_intensity_face_sptr f = this->generate_sample(seed->face());
00503 strk_correlated_face* cf = new strk_correlated_face();
00504 cf->set_face(f);
00505 int n = f->Npix();
00506
00507 for (int i = 0; i<n; i++)
00508 {
00509 cf->set_Ix(i, seed->Ix(i));
00510 cf->set_Iy(i, seed->Iy(i));
00511 }
00512 return cf;
00513 }
00514
00515
00516
00517 strk_correlated_face*
00518 strk_tracker::regenerate_cf_sample(strk_correlated_face* sample)
00519 {
00520 if (!sample)
00521 return 0;
00522 vtol_face_2d_sptr f = sample->face()->cast_to_face_2d();
00523 vtol_intensity_face_sptr intf = new vtol_intensity_face(f);
00524 this->fill_face(intf, image_i_);
00525 strk_correlated_face* cf = new strk_correlated_face();
00526 cf->set_face(intf);
00527 this->set_gradient(cf, Ix_i_, Iy_i_);
00528 return cf;
00529 }
00530
00531
00532
00533 void strk_tracker::transform_sample_in_place(strk_correlated_face* sample,
00534 double tx, double ty,
00535 double theta, double scale)
00536 {
00537 if (!sample)
00538 return;
00539 vtol_intensity_face_sptr face = sample->face();
00540 float xo = face->Xo(), yo = face->Yo();
00541 double c = vcl_cos(theta), s = vcl_sin(theta);
00542 vcl_vector<vtol_vertex_sptr> verts;
00543 face->vertices(verts);
00544 for (vcl_vector<vtol_vertex_sptr>::iterator vit = verts.begin();
00545 vit != verts.end(); vit++)
00546 {
00547 vtol_vertex_2d_sptr v = (*vit)->cast_to_vertex_2d();
00548 if (!v)
00549 continue;
00550 double x = v->x(), y = v->y();
00551 double xp =(x-xo)*scale, yp =(y-yo)*scale;
00552 v->set_x(xp*c - yp*s + xo + tx);
00553 v->set_y(xp*s + yp*c + yo + ty);
00554 }
00555 for (face->reset(); face->next();)
00556 {
00557 float x = face->X(), y = face->Y();
00558 double xp =(x-xo)*scale, yp =(y-yo)*scale;
00559 face->set_X(float(xp*c - yp*s + xo + tx));
00560 face->set_Y(float(xp*s + yp*c + yo + ty));
00561 }
00562 }
00563
00564
00565
00566 void strk_tracker::generate_samples()
00567 {
00568 vul_timer t;
00569 for (vcl_vector<strk_correlated_face*>::iterator fit =
00570 current_samples_.begin(); fit != current_samples_.end(); fit++)
00571 for (int i = 0; i<n_samples_; i++)
00572 {
00573 strk_correlated_face* cf = this->generate_cf_sample(*fit);
00574 this->correlate_face(cf);
00575 hypothesized_samples_.push_back(cf);
00576 }
00577
00578 vcl_sort(hypothesized_samples_.begin(),
00579 hypothesized_samples_.end(), corr_compare);
00580 }
00581
00582
00583
00584 void strk_tracker::cull_samples()
00585 {
00586 for (vcl_vector<strk_correlated_face*>::iterator
00587 cit = current_samples_.begin();
00588 cit != current_samples_.end(); cit++)
00589 delete *cit;
00590 current_samples_.clear();
00591
00592 for (int i =0; i<n_samples_; i++)
00593 {
00594 #ifdef DEBUG
00595 vcl_cout << "Corr = " << hypothesized_samples_[i]->correlation() << '\n';
00596 vcl_cout << vcl_flush;
00597 #endif //DEBUG
00598 current_samples_.push_back(hypothesized_samples_[i]);
00599 }
00600
00601 for (unsigned int i=n_samples_; i<hypothesized_samples_.size(); ++i)
00602 delete hypothesized_samples_[i];
00603 hypothesized_samples_.clear();
00604 }
00605
00606
00607
00608 vtol_face_2d_sptr strk_tracker::get_best_sample()
00609 {
00610 if (!current_samples_.size())
00611 return 0;
00612 return current_samples_[0]->face()->cast_to_face_2d();
00613 }
00614
00615
00616
00617 void strk_tracker::get_samples(vcl_vector<vtol_face_2d_sptr>& samples)
00618 {
00619 samples.clear();
00620 for (vcl_vector<strk_correlated_face*>::iterator
00621 fit = current_samples_.begin(); fit != current_samples_.end(); fit++)
00622 samples.push_back((*fit)->face()->cast_to_face_2d());
00623 }
00624
00625
00626
00627 void strk_tracker::track()
00628 {
00629 vul_timer t;
00630 this->generate_samples();
00631 this->cull_samples();
00632
00633
00634 }
00635
00636 void strk_tracker::clear()
00637 {
00638 current_samples_.clear();
00639 for (vcl_vector<strk_correlated_face*>::iterator
00640 cit = hypothesized_samples_.begin();
00641 cit != hypothesized_samples_.end(); cit++)
00642 delete *cit;
00643 hypothesized_samples_.clear();
00644 }