00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef ACTIVE_CONTOUR_H
00010 #define ACTIVE_CONTOUR_H
00011
00012
00013
00014 #include <iostream>
00015 #include <fstream>
00016 #include <list>
00017 #include <cstring>
00018 #include <cmath>
00019 #include <values.h>
00020 #include "cartesian.h"
00021 #include "image.h"
00022 #include "image_fileoutput.h"
00023 #include "image_funcs.h"
00024
00025 namespace mimas {
00026
00027 template<typename T>
00028 class activeContour : public image <T>
00029 {
00030 protected:
00031 int numPolyPoints;
00032
00033 private:
00034
00035 int pointInPolygon(int x, int y);
00036 image<double> imageEnergy;
00037 double eucDist(double x1, double y1, double x2, double y2);
00038 void computeImageEnergy(const const_image_ref<T> &inputImage);
00039
00040 public:
00041 void pushPolyCoord(int xcoord, int ycoord);
00042 void showPolyCoords(void);
00043 void clearPolyCoords(void);
00044 void sortPolyCoords(void);
00045 void showPolygonOnImage( image_ref<T> &someImage);
00046
00047 void setPolyCircle(int xcenter, int ycenter, int circleRadius, int numPoints);
00048 int adaptContour( const const_image_ref<T> &inputImage );
00049 std::list< Cartesian<int> > adaptContourList( const const_image_ref<T> &trackingImage );
00050 std::list< Cartesian<int> > polyCoords;
00051
00052
00053 int maxTotalPointsMoved;
00054 int maxNumIterations;
00055 double alpha, beta, gamma;
00056 #ifndef NDEBUG
00057 bool debug;
00058 #endif
00059 bool smooth;
00060 int showPolygonOnImage_graylevel, showPolygonOnImage_thickness;
00061
00062
00063 activeContour()
00064 {
00065 numPolyPoints=0;
00066 maxTotalPointsMoved=4000;
00067 maxNumIterations=1000;
00068 alpha=1.0;
00069 beta=1.0;
00070 gamma=5.0;
00071 #ifndef NDEBUG
00072 debug=false;
00073 #endif
00074 smooth=false;
00075 showPolygonOnImage_graylevel=127;
00076 showPolygonOnImage_thickness=1;
00077 }
00078
00079
00080 ~activeContour()
00081 {
00082
00083 }
00084 };
00085
00086
00087 template<typename T>
00088 double activeContour<T>::eucDist(double x1, double y1, double x2, double y2)
00089 {
00090 return sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)));
00091 }
00092
00093
00094 template<typename T>
00095 int activeContour<T>::adaptContour( const const_image_ref<T> &inputImage )
00096 {
00097 int j, k, jmin, kmin;
00098 int pointcount, ptsmoved, totptsmoved=0, itercount=0;
00099 double Esnake, Emin, E, Eimage, aveDist;
00100 double Econt[9], Econtmax, Econtmin;
00101 double Ecurv[9], Ecurvmax, Ecurvmin;
00102
00103 std::list< Cartesian<int> >::iterator curpoint, prevpoint, nextpoint;
00104
00105 computeImageEnergy(inputImage);
00106
00107 do
00108 {
00109
00110 aveDist=0.0;
00111 for(curpoint=polyCoords.begin(), prevpoint=--polyCoords.end() ; curpoint != polyCoords.end(); prevpoint=curpoint,++curpoint)
00112 {
00113 aveDist+=eucDist((*curpoint).x,(*curpoint).y,(*prevpoint).x,(*prevpoint).y);
00114 }
00115 aveDist=aveDist/(double)numPolyPoints;
00116
00117
00118 ptsmoved=0;
00119 Esnake=0.0;
00120
00121
00122
00123
00124 prevpoint=--polyCoords.end();
00125 nextpoint=++polyCoords.begin();
00126 for (curpoint=polyCoords.begin(); curpoint != polyCoords.end(); prevpoint++, curpoint++, nextpoint++)
00127 {
00128
00129
00130 if (prevpoint==polyCoords.end()) prevpoint=polyCoords.begin();
00131 if (nextpoint==polyCoords.end()) nextpoint=polyCoords.begin();
00132
00133
00134 for (j=-1, pointcount=0, Econtmax=Ecurvmax=-FLT_MAX, Econtmin=Ecurvmin=FLT_MAX; j<=1; j++)
00135 for (k=-1; k<=1; k++, pointcount++)
00136 {
00137
00138 Econt[pointcount]=fabs(aveDist-
00139 eucDist( (*prevpoint).x, (*prevpoint).y,
00140 (*curpoint).x + k, (*curpoint).y + j ) );
00141
00142 if (Econt[pointcount]>Econtmax) Econtmax=Econt[pointcount];
00143 if (Econt[pointcount]<Econtmin) Econtmin=Econt[pointcount];
00144
00145
00146 Ecurv[pointcount]=
00147 ((*prevpoint).x - 2.0 * ((*curpoint).x + k) + (*nextpoint).x) *
00148 ((*prevpoint).x - 2.0 * ((*curpoint).x + k) + (*nextpoint).x) +
00149 ((*prevpoint).y - 2.0 * ((*curpoint).y + j) + (*nextpoint).y) *
00150 ((*prevpoint).y - 2.0 * ((*curpoint).y + j) + (*nextpoint).y);
00151
00152 if (Ecurv[pointcount]>Ecurvmax) Ecurvmax=Ecurv[pointcount];
00153 if (Ecurv[pointcount]<Ecurvmin) Ecurvmin=Ecurv[pointcount];
00154 }
00155
00156
00157
00158 for (j=-1, pointcount=0, jmin=kmin=0, Emin=FLT_MAX; j<=1; j++)
00159 for (k=-1; k<=1; k++, pointcount++)
00160 {
00161 if (Econtmax != Econtmin) Econt[pointcount]=(Econt[pointcount]-Econtmin)/(Econtmax-Econtmin);
00162 if (Ecurvmax != Ecurvmin) Ecurv[pointcount]=(Ecurv[pointcount]-Ecurvmin)/(Ecurvmax-Ecurvmin);
00163 Eimage = imageEnergy.getPixel((*curpoint).x + k, (*curpoint).y + j);
00164
00165 E = alpha * Econt[pointcount] + beta * Ecurv[pointcount] + gamma * Eimage;
00166
00167 if (E < Emin)
00168 { Emin = E; jmin = j; kmin = k; }
00169 }
00170
00171
00172 Esnake += Emin;
00173
00174
00175 if ((jmin!=0) || (kmin!=0))
00176 {
00177 (*curpoint).y = (*curpoint).y + jmin;
00178 (*curpoint).x = (*curpoint).x + kmin;
00179 ptsmoved++; totptsmoved++;
00180 }
00181 }
00182 #ifndef NDEBUG
00183 if (debug) std::cerr << itercount << " " << totptsmoved << std::endl;
00184 #endif
00185
00186
00187
00188 #ifndef NDEBUG
00189 if (debug)
00190 {
00191 image<int> debugimage( inputImage );
00192
00193 showPolygonOnImage(debugimage);
00194 char framefilename[80];
00195 sprintf(framefilename,"frame%.3d.pgm", itercount);
00196 std::ofstream file( framefilename, std::ios::binary );
00197 file << debugimage;
00198 debugimage.clear();
00199 }
00200 #endif
00201
00202 } while ((++itercount < maxNumIterations) && (totptsmoved < maxTotalPointsMoved) && (ptsmoved > 0));
00203
00204
00205 std::list< Cartesian<int> > ::iterator m;
00206 for(m=polyCoords.begin(); m != polyCoords.end(); m++)
00207 {
00208 if ((*m).x<0) (*m).x=0;
00209 if ((*m).x>=inputImage.getWidth()) (*m).x=inputImage.getWidth()-1;
00210 if ((*m).y<0) (*m).y=0;
00211 if ((*m).y>=inputImage.getHeight()) (*m).y=inputImage.getHeight()-1;
00212 }
00213
00214
00215
00216 return (itercount);
00217 }
00218
00219
00220 template<typename T>
00221 void activeContour<T>::setPolyCircle(int xcenter, int ycenter, int circleRadius, int numPoints)
00222 {
00223 double angle;
00224 int count;
00225
00226
00227 for (angle=0.0, count=0; angle<360.0; angle+=(360.0/numPoints))
00228 {
00229
00230
00231
00232
00233
00234 pushPolyCoord((int)(xcenter+circleRadius*cos(angle*M_PI/180.0)),
00235 (int)(ycenter-circleRadius*sin(angle*M_PI/180.0)));
00236
00237 if (++count==numPoints) break;
00238 }
00239 }
00240
00241
00242 template<typename T>
00243 void activeContour<T>::computeImageEnergy(const const_image_ref<T> &inputImage)
00244 {
00245 if (smooth)
00246 imageEnergy = edgeSobelSqr( softenHeavy( inputImage ) );
00247 else
00248 imageEnergy = edgeSobelSqr( inputImage );
00249
00250 double
00251 minval = min_val( imageEnergy ),
00252 maxval = max_val( imageEnergy );
00253
00254
00255 if ((maxval-minval)<5.0) maxval=minval+5.0;
00256
00257
00258 imageEnergy = ( imageEnergy - minval ) * ( 1.0 / ( maxval - minval ) );
00259 }
00260
00261
00262
00263
00264 template<typename T>
00265 void activeContour<T>::pushPolyCoord(int xcoord, int ycoord)
00266 {
00267
00268
00269 Cartesian<int> tempcoord;
00270 tempcoord.x=xcoord;
00271 tempcoord.y=ycoord;
00272
00273 polyCoords.push_back(tempcoord);
00274
00275 numPolyPoints++;
00276 }
00277
00278
00279 template<typename T>
00280 void activeContour<T>::showPolyCoords(void)
00281 {
00282 std::list< Cartesian<int> > ::iterator i;
00283
00284 for(i=polyCoords.begin(); i != polyCoords.end(); ++i)
00285 std::cout << *i << std::endl;
00286 }
00287
00288 template<typename T>
00289 void activeContour<T>::clearPolyCoords(void)
00290 {
00291 polyCoords.clear();
00292 }
00293
00294
00295 template<typename T>
00296 void activeContour<T>::sortPolyCoords(void)
00297 {
00298 polyCoords.sort();
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 template<typename T>
00328 int activeContour<T>::pointInPolygon(int x, int y)
00329 {
00330 std::list< Cartesian<int> > ::iterator i,j;
00331 int c = 0;
00332
00333
00334 for(i=polyCoords.begin(), j=--polyCoords.end() ; i != polyCoords.end(); j=i,++i)
00335 {
00336 if (((((*i).y<=y) && (y<(*j).y)) ||
00337 (((*j).y<=y) && (y<(*i).y))) &&
00338 (x < ((*j).x - (*i).x) * (y - (*i).y) / ((*j).y - (*i).y) + (*i).x))
00339 c = !c;
00340 }
00341
00342 return c;
00343 }
00344
00345
00346 template<typename T>
00347 void activeContour<T>::showPolygonOnImage( image_ref<T> &someImage)
00348 {
00349 std::list< Cartesian<int> > ::iterator i,j;
00350 for(i=polyCoords.begin(), j=--polyCoords.end() ; i != polyCoords.end(); j=i,++i)
00351 if (showPolygonOnImage_thickness == 1)
00352 drawLine(someImage, (*i).x, (*i).y, (*j).x, (*j).y, showPolygonOnImage_graylevel);
00353 else
00354 drawThickLine(someImage, (*i).x, (*i).y, (*j).x, (*j).y, showPolygonOnImage_graylevel, 5);
00355 }
00356
00357
00358
00359 template<typename T>
00360 std::list< Cartesian<int> > activeContour<T>::adaptContourList( const const_image_ref<T> &trackingImage )
00361 {
00362 std::list< Cartesian<int> > ::iterator i;
00363 std::list< Cartesian<int> > outCoordList;
00364 Cartesian<int> tempcoord;
00365
00366
00367 adaptContour(trackingImage);
00368
00369 for(i=polyCoords.begin(); i != polyCoords.end(); i++)
00370 {
00371 tempcoord.x=(*i).x;
00372 tempcoord.y=(*i).y;
00373 outCoordList.push_back(tempcoord);
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 return outCoordList;
00389 }
00390
00391 }
00392
00393 #endif