Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleTrackerBase.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003, 2004 (see file CONTACTS for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 /** @example ExampleTrackerBase.cpp
26  @relates TrackerBaseSimple
27  @brief This little example evaluates a TrackerBase class against synthetically
28  generated ground truth data.
29  Synthetically generated ground truth data can be found in the TestData
30  repository in our cvs.
31 
32  ExampleTrackerBase 157 157 ~/cvs/TestData/tracker_noise/image*.pgm
33 
34  @ingroup g_examples
35  @author woelk
36 */
37 
38 
39 #include <Matcher2D/TrackerBaseSimple.hh>
40 #include <Base/Image/Image.hh>
41 #include <Base/ImageUtils/ImageDraw.hh>
42 #include <Base/Image/ImageIO.hh>
43 #include <Base/Image/ImageConvert.hh>
44 #include <Base/Geometry/HomgPoint2D.hh>
45 #include <Base/Debug/TimeMeasure.hh>
46 #include <Filter/GradientSobel3x3.hh>
47 #include <Filter/GradientGauss.hh>
48 #include <Filter/GradientGaussAsymmetric.hh>
49 #include <Filter/Binomial.hh>
50 
51 #include <iostream>
52 #include <iomanip>
53 
54 using namespace BIAS;
55 using namespace std;
56 
57 
58 // always track using float image, since it is a lot faster
59 #define StorageType float
60 
61 // default parameter file name
62 #define DEFAULT_PARA_FILE_NAME "TrackerBase.ini"
63 
64 
65 /// loads an image and converts to single channel float image
66 int LoadImage(char *name, Image<StorageType>& im)
67 {
68  ImageBase baseim;
69 
70  // load image
71  if (ImageIO::Load(name, baseim)!=0){
72  BIASERR("error loading image "<<name);
73  return -1;
74  }
75  // convert to float
76  if (ImageConvert::ConvertST(baseim, im, ImageBase::ST_float)!=0){
77  BIASERR("error converting image "<<name);
78  return -2;
79  }
80  // convert to grey if necessary
81  if (im.GetChannelCount()!=1){
82  if (ImageConvert::ToGrey(im, im)!=0){
83  BIASERR("error converting image to grey "<<name);
84  return -3;
85  }
86  }
87  im.SetMetaData(*baseim.GetMetaData());
88 
89  //ImageIO::Save("fimage.mip", im);
90  return 0;
91 }
92 
93 /// draws the tracking result and saves to name.tracked
94 void Draw(Image<StorageType>& im, HomgPoint2D& p, Matrix2x2<KLT_TYPE>& cov,
95  char *name)
96 {
98  unsigned uip[2], radius=1;
99  unsigned char color[]={255,0,0};
100  string file;
101  float cov_scale=1e5;
102  bool draw_cov=true;
103 
104 
105  // convert to unsigned char
107  BIASERR("error converting image to unsigned char "<<name);
108  BIASABORT;
109  }
110 
111  // convert to rgb if necessary
112  if (dim.GetColorModel()!=ImageBase::CM_RGB){
113  if (ImageConvert::ToRGB(dim, dim)!=0){
114  BIASERR("error converting image to RGB "<<name);
115  BIASABORT;
116  }
117  }
118 
119  uip[0]=(unsigned int)rint(p[0]);
120  uip[1]=(unsigned int)rint(p[1]);
121 
123  CircleCenterFilled(dim, uip[0], uip[1], radius, color);
124 
125  if (draw_cov){
126  double center[2], a[2], b[2], eva, evb;
127  Vector2<double> na, nb;
128  center[0]=p[0];
129  center[1]=p[1];
130 
131  cov.EigenvalueDecomposition(eva, na, evb, nb);
132  cout << eva<<", "<<evb<<"\n";
133  a[0]=na[0]*eva*cov_scale;
134  a[1]=na[1]*eva*cov_scale;
135  b[0]=nb[0]*evb*cov_scale;
136  b[1]=nb[1]*evb*cov_scale;
138  Ellipse(dim, center, a, b, color);
139  }
140 
141  file=name;
142  file+=".tracked";
143  //ImageIO::Save(file, dim);
144  ImageIO::Save(file, dim);
145  cout << "wrote "<<file<<endl;
146 }
147 
148 /// the main function
149 int main(int argc, char*argv[])
150 {
151  Param para;
152  para.SetWriteOptions(false, false, false);
153  Image<StorageType> fim[2], im[2], drawim;
154  Image<StorageType> gradx[2], grady[2];
155  KLT_TYPE error, err, residuumMAD, residuumMSD, errorsum=0.0;
156  HomgPoint2D p[2];
158  int newim, oldim, iter;
159  int res, counter;
160  bool debug=false;
161  bool draw=true;
162  MetaData *md;
163  AppData appdata;
164  HomgPoint2D realpoint;
165 
172  ggaussasymmetric(para);
173  int *gradienttype = AddGradientType(para);
174  Binomial<StorageType, StorageType> binomial(para);
175 
176  TimeMeasure timer, tc;
177 
178  int argind = para.UpdateParameter(argc, argv, DEFAULT_PARA_FILE_NAME);
179 
180  if (argc-argind<4 || argind<1){
181  cerr << argv[0] << " : <x-coo> <y-coo> <image> <image> ..."<< endl;
182  return -5;
183  }
184 
185  // activate some debugging output of tracking object
186  //tracker.AddDebugLevel(D_TRACKERB_INIT);
187  //tracker.AddDebugLevel(D_TRACKERB_SKLT);
188  //tracker.AddDebugLevel(D_TRACKERB_GKLT);
189  //tracker.AddDebugLevel(D_TRACKERB_BILINEAR);
190 
191  // choose the gradient type according to parameter
192  switch (*gradienttype){
193  case GT_Sobel3x3:
194  grad = &gsobel3x3;
195  cerr <<"Sobel3x3\n";
196  break;
197  case GT_Gauss:
198  grad = &ggauss;
199  cerr <<"GradientGauss\n";
200  break;
201  case GT_GaussAsymmetric:
202  grad = &ggaussasymmetric;
203  cerr <<"GradientGaussAsymmetric\n";
204  break;
205  default:
206  BIASERR("unknown gradient type");
207  grad = NULL;
208  break;
209  }
210  // activate some debugging output of gradient object
211  //grad->AddDebugLevel(D_GRADGAUSS_KERNEL);
212  //grad->AddDebugLevel(D_CONV_KERNEL);
213 
214  // get the point to track from command line
215  p[0][2]=p[1][2]=1.0;
216  p[0][0]=atof(argv[argind]);
217  p[0][1]=atof(argv[argind+1]);
218  cout << "attempt to track point "<<p[0] << endl;
219 
220 
221  // load image
222  if (LoadImage(argv[argind+2], im[0])!=0){
223  BIASERR("error loading image "<<argv[argind+2]);
224  return -1;
225  }
226 
227  // calculate gradients and low pass filtered images
228  binomial.Filter3x3(im[0], fim[0]);
229  grad->Filter(fim[0], gradx[0], grady[0]);
230 
231 
232  counter=argind+2;
233  newim=0;
234  // now loop through the images
235  while (counter < argc-1){
236  counter++;
237  newim=(newim==0)?(1):(0);
238  oldim=(newim==0)?(1):(0);
239 
240  if (LoadImage(argv[counter], im[newim])!=0){
241  BIASERR("error loading image "<<argv[counter]);
242  return -1;
243  } else {
244  if (debug)
245  cout << "\n------- newim: " << argv[counter]
246  << "\n------- oldim: " << argv[counter-1] << endl;
247 
248  md=im[newim].GetMetaData();
249  if (md->Find(AppData::MD_HomgPoint2D, "#[HomgPoint2D]", appdata)>=0){
250  if (appdata.tag==AppData::MD_USE_ASCII){
251  if (debug) cerr << appdata.stag <<" : "<<appdata.sdata<<endl;
252  sscanf(appdata.sdata.c_str(), "[ %lf %lf %lf ]",
253  &realpoint[0], &realpoint[1], &realpoint[2]);
254  } else {
255  memcpy(realpoint.GetData(), appdata.data, appdata.length);
256  }
257  if (debug) cerr <<"realpoint is at "<<realpoint<<endl;
258  } else {
259  BIASERR("cannot find HomgPoint2D in meta data");
260  }
261  }
262 
263  // calculate gradients and low pass filtered images
264  binomial.Filter3x3(im[newim], fim[newim]);
265  grad->Filter(fim[newim], gradx[newim], grady[newim]);
266 
267  // time the tracking
268  timer.Start();
269  tc.Start();
270 
271 #ifdef BIAS_DEBUG
272  //ImageIO::Save("im1.mip", im[oldim]);
273  //ImageIO::Save("im2.mip", im[newim]);
274  //ImageIO::Save("fim1.mip", fim[oldim]);
275  //ImageIO::Save("fim2.mip", fim[newim]);
276  //ImageIO::Save("gx1.mip", gradx[oldim]);
277  //ImageIO::Save("gx2.mip", gradx[newim]);
278  //ImageIO::Save("gy1.mip", grady[oldim]);
279  //ImageIO::Save("gy2.mip", grady[newim]);
280  ImageIO::Save("im1.mip", im[oldim]);
281  ImageIO::Save("im2.mip", im[newim]);
282  ImageIO::Save("fim1.mip", fim[oldim]);
283  ImageIO::Save("fim2.mip", fim[newim]);
284  ImageIO::Save("gx1.mip", gradx[oldim]);
285  ImageIO::Save("gx2.mip", gradx[newim]);
286  ImageIO::Save("gy1.mip", grady[oldim]);
287  ImageIO::Save("gy2.mip", grady[newim]);
288  cerr << "Tracking from "<<p[oldim]<<" --> "<<p[oldim]<<endl;
289 #endif
290 
291  // first: initialize the tracker
292  tracker->Init(fim[oldim], fim[newim], gradx[oldim], grady[oldim],
293  gradx[newim], grady[newim]);
294 
295  // second: do the tracking
296  res =
297  tracker->Track(p[oldim], p[oldim], p[newim], error, iter,
298  residuumMAD, residuumMSD, cov);
299 
300  // time the tracking
301  tc.Stop();
302  timer.Stop();
303  tc.Print();
304  tc.Reset();
305 
306  // check for errors
307  if (res<0){
308  // stop looping through images if point vanishes from the valid
309  // image region
310  if (res==-2){
311  cout << "point ("<<p[oldim][0]<<", "<<p[oldim][1]<<") too close to "
312  <<"image border, stopping"<<endl;
313  break;
314  }
315  BIASERR("error matching "<<res);
316  assert(false);
317  }
318 
319  // calculate the error with respect to ground truth from image header
320  err=sqrt((p[newim][0]-realpoint[0])*(p[newim][0]-realpoint[0])+
321  (p[newim][1]-realpoint[1])*(p[newim][1]-realpoint[1]));
322  errorsum+=err;
323 
324  // draw and save the result
325  if (draw)
326  Draw(im[newim], p[newim], cov, argv[counter]);
327 
328  cout << setw(2) << counter-3 << " : (" << p[oldim][0]<<", "<<p[oldim][1]
329  << ") -> ("<< p[newim][0]<<", "<<p[newim][1]<<") klt-error: "<<error
330  <<" real: ("<<realpoint[0]<<", "<<realpoint[1]
331  <<") dist-err: "<<err<<" residuumMAD: "<<residuumMAD
332  <<" residuumMSD: "<<residuumMSD<<endl;
333 
334  }
335  // print out some statistics
336  cerr << "errorsum over "<<counter-3<<" images: "<<errorsum<<endl
337  << " mean error "<<errorsum/(double)(counter-3)<<endl;
338 
339  timer.Print();
340  cerr << "KLT trackin over "<<argc-3<<" images took "<<timer.GetRealTime()
341  <<" us"
342  << "\n this is equal to "<<timer.GetRealTime()/double(argc-3)
343  <<" us per image and corner" << endl;
345  return 0;
346 }
347 
void Print(std::ostream &os=std::cout) const
std::string stag
the tag as given in ascii meta data
Definition: MetaData.hh:100
const T * GetData() const
get the data pointer the member function itself is const (before {..}) because it doesn&#39;t change the ...
Definition: Vector3.hh:202
gradient calculation with separated gauss masks
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
int UpdateParameter(int &argc, char *argv[], const std::string &default_filename)
update all arguments from command line and parameter file
Definition: Param.cpp:985
void Init(Image< StorageType > &im1, Image< StorageType > &im2, Image< StorageType > &gradx1, Image< StorageType > &grady1, Image< StorageType > &gradx2, Image< StorageType > &grady2)
Prepare for tracking with prefiltered images.
Base class for the different tracking algorithms, defining the interfaces for the tracking functions...
base class for simple n-&gt;2n filter implementations
Definition: FilterNTo2N.hh:44
void DisableDestructorWarning()
Uses this just before end of your program to avoid error from destructor.
Definition: Param.hh:513
MetaData * GetMetaData()
Definition: ImageBase.hh:456
float image storage type
Definition: ImageBase.hh:118
static int CircleCenterFilled(Image< StorageType > &im, unsigned int CenterX, unsigned int CenterY, unsigned int Radius, const StorageType Value[])
draws a filled circle using Value
Definition: ImageDraw.cpp:1023
int length
number of bytes used by the data block
Definition: MetaData.hh:96
gradient calculation with sobel 3 by 3 masks
std::string sdata
the data as given in ascii meta data
Definition: MetaData.hh:102
char * data
pointer to block of data
Definition: MetaData.hh:98
int Track(HomgPoint2D &p1, HomgPoint2D &p2, HomgPoint2D &p2tracked, KLT_TYPE &error, int &iter, KLT_TYPE &residuumMAD, KLT_TYPE &residuumMSD, Matrix< KLT_TYPE > &cov, const Matrix2x2< KLT_TYPE > &AffinePred=Matrix2x2< KLT_TYPE >(MatrixIdentity), Matrix2x2< KLT_TYPE > *AffineResult=NULL)
Calculates correspondence from image1 to image2.
static int ConvertST(const BIAS::ImageBase &source, BIAS::ImageBase &dest, ImageBase::EStorageType targetST)
Function to convert the storage type of images e.g.
static int Ellipse(Image< StorageType > &im, double center[2], double a[2], double b[2], const StorageType Value[])
draws an ellipse at center with half axes a and b
Definition: ImageDraw.cpp:1255
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
color values, 3 channels, order: red,green,blue
Definition: ImageBase.hh:131
int Find(const enum AppData::TAppData tag, AppData &data) const
searches for tag in binary coded AppDatas.
Definition: MetaData.cpp:363
The image template class for specific storage types.
Definition: Image.hh:78
static int Save(const std::string &filename, const ImageBase &img, const enum TFileFormat FileFormat=FF_auto, const bool sync=BIAS_DEFAULT_SYNC, const int c_jpeg_quality=BIAS_DEFAULT_IMAGE_QUALITY, const bool forceNewID=BIAS_DEFAULT_FORCENEWID, const bool &writeMetaData=true)
Export image as file using extrnal libs.
Definition: ImageIO.cpp:725
enum TAppData tag
The tag defines the type of data, e.g.
Definition: MetaData.hh:94
double GetRealTime() const
return real time (=wall time clock) in usec JW For Win32: real-time is measured differently from user...
gradient calculation with separated gauss masks
int EigenvalueDecomposition(T &value1, Vector2< T > &vector1, T &value2, Vector2< T > &vector2) const
Eigenvalue decomposition.
Definition: Matrix2x2.cpp:131
enum EColorModel GetColorModel() const
Definition: ImageBase.hh:407
This class Param provides generic support for parameters.
Definition: Param.hh:231
static int Load(const std::string &FileName, ImageBase &img)
first tries a call to Read MIP image and if that fails, tries to Import Image with all other availabl...
Definition: ImageIO.cpp:141
this class collects all additional data chunks of type AppData to be written into/read from an image ...
Definition: MetaData.hh:121
(8bit) unsigned char image storage type
Definition: ImageBase.hh:112
void SetWriteOptions(bool indent, bool comments, bool enhanced)
Definition: Param.hh:530
void SetMetaData(const MetaData &m)
Definition: ImageBase.hh:470
This is the base class for images in BIAS.
Definition: ImageBase.hh:102
static int ToRGB(const Image< StorageType > &source, Image< StorageType > &dest)
Create a RGB converted copy of source image in this.
binomial low pass filter class
Definition: Binomial.hh:42
class TimeMeasure contains functions for timing real time and cpu time.
Definition: TimeMeasure.hh:111
this is a chunk of metadata, also see MetaData
Definition: MetaData.hh:49
static int ToGrey(const ImageBase &source, ImageBase &dest)
wrapper for the templated function ToGrey