/home/oan/prosjekt/gotools/segmentation/gpl_distro/lsseg_1.0_gpl/app/smoothcurvpres.C

Go to the documentation of this file.
00001 //===========================================================================
00002 // The Level-Set Segmentation Library (LSSEG)
00003 //
00004 //
00005 // Copyright (C) 2000-2005 SINTEF ICT, Applied Mathematics, Norway.
00006 //
00007 // This program is free software; you can redistribute it and/or          
00008 // modify it under the terms of the GNU General Public License            
00009 // as published by the Free Software Foundation version 2 of the License. 
00010 //
00011 // This program is distributed in the hope that it will be useful,        
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of         
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
00014 // GNU General Public License for more details.                           
00015 //
00016 // You should have received a copy of the GNU General Public License      
00017 // along with this program; if not, write to the Free Software            
00018 // Foundation, Inc.,                                                      
00019 // 59 Temple Place - Suite 330,                                           
00020 // Boston, MA  02111-1307, USA.                                           
00021 //
00022 // Contact information: e-mail: tor.dokken@sintef.no                      
00023 // SINTEF ICT, Department of Applied Mathematics,                         
00024 // P.O. Box 124 Blindern,                                                 
00025 // 0314 Oslo, Norway.                                                     
00026 // 
00027 //
00028 // Other licenses are also available for this software, notably licenses
00029 // for:
00030 // - Building commercial software.                                        
00031 // - Building software whose source code you wish to keep private.        
00032 //
00033 //===========================================================================
00034 #include <fstream>
00035 #include <limits>
00036 #include <iostream>
00037 #include <assert.h>
00038 #include <time.h>
00039 #include <boost/tokenizer.hpp>
00040 
00041 #include "Image.h"
00042 #include "Filters.h"
00043 #include "LIC.h"
00044 #include "simple_tools.h"
00045 #include"cimg_dependent.h"
00046 
00047 using namespace std;
00048 using namespace lsseg;
00049 
00050 const double PI = 3.1415926535897932384;
00051 
00052 // argument that may be overridden by command line
00054 double DT = 30; 
00056 double DL = 0.8; 
00058 double ALPHA = 1.2; 
00060 double SIGMA = 1; 
00062 int NUM_TIMESTEPS = 1;
00065 double P1 = 0.3; 
00068 double P2 = 0.7;
00071 double P3 = 0.9; 
00073 double L = 2 * sqrt(DT); 
00075 const int DIV_THETA = 6; 
00077 const double DTHETA = PI / DIV_THETA;
00079 const int DIV_PHI = 6; 
00081 const double DPHI = PI / DIV_PHI;
00083 const char SAVED_3D_FILE[] = "greycstoration_result.stack";  
00084 
00085 double C = double(1) / sqrt(4 * PI * DT); // factor used in gauss
00086 double D = double(1) / (4 * DT);
00087 
00088 //===========================================================================
00089 void make_vector_field_2D(double angle, const Image<double>& tensor, Image<double>& vec);
00090 //===========================================================================
00091 
00092 //===========================================================================
00093 void make_vector_field_3D(double phi, double theta, const Image<double>& tensor, Image<double>& vec);
00094 //===========================================================================
00095 
00096 //===========================================================================
00097 void show_command_info();
00098 //===========================================================================
00099 
00100 //===========================================================================
00101 void show_current_vars();
00102 //===========================================================================
00103 
00104 //===========================================================================
00105 void read_command_info(int varnum, char** vararg);
00106 //===========================================================================
00107 
00108 //===========================================================================
00109 double gauss(double t) 
00110 //===========================================================================
00111 {
00112     //return 1; // @@
00113     const double res = C * exp(-(t*t) * D);
00114     return res;
00115 }
00116 
00117 //===========================================================================
00118 bool refers_to_stack(string str)
00119 //===========================================================================
00120 {
00121     typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00122     boost::char_separator<char> sep(".");
00123     tokenizer tokens(str, sep);
00124     string saved;
00125     for (tokenizer::iterator it = tokens.begin(); it != tokens.end(); ++it) {
00126         saved = *it;
00127     }
00128     if (saved == string("stack") || saved == string("Stack") || saved == string("STACK")) {
00129         return true;
00130     }
00131     return false;
00132 }
00133 
00134 //===========================================================================
00135 void to_field(const Image<double>& T, Image<double>& W)
00136 //===========================================================================
00137 {
00138     const int X = T.dimx();
00139     const int Y = T.dimy();
00140     const int Z = T.dimz();
00141     W.resize(X, Y, Z, 4);
00142     for (int z = 0; z < Z; ++z) {
00143         for (int y = 0; y < Y; ++y) {
00144             for (int x = 0; x < X; ++x) {
00145                 double wx = T(x, y, z, 0);
00146                 double wy = T(x, y, z, 1);
00147                 double wz = T(x, y, z, 2);
00148                 double norm = sqrt(wx * wx + wy * wy + wz*wz);
00149                 double norm_inv = (norm == 0) ? 1 : double(1) / norm;
00150                 W(x, y, z, 0) = wx * norm_inv;
00151                 W(x, y, z, 1) = wy * norm_inv;
00152                 W(x, y, z, 2) = wz * norm_inv;
00153                 W(x, y, z, 3) = norm;
00154             }
00155         }
00156     }
00157 }
00158 
00159 void make_debug_field(const Image<double>& T, Image<double>& W)
00160 {
00161     //to_field(T, W); return; //@
00162 
00163     const int X = T.dimx();
00164     const int Y = T.dimy();
00165     const int Z = T.dimz();
00166     W.resize(X, Y, Z, 4);
00167     for (int z = 0; z < Z; ++z) {
00168         for (int y = 0; y < Y; ++y) {
00169             for (int x = 0; x < X; ++x) {
00170                 double vx = (x - X/2+0.5);
00171                 double vy = (y - Y/2 +0.5);
00172                 double vz =(z - Z/2 + 0.5);
00173                 double norm = sqrt(vx * vx + vy * vy + vz * vz);
00174                 vx /= norm;
00175                 vy /= norm;
00176                 vz /= norm;
00177                 
00178                 W(x, y, z, 0) = vx;
00179                 W(x, y, z, 1) = vy;
00180                 W(x, y, z, 2) = vz;
00181                 W(x, y, z, 3) = 1;
00182             }
00183         }
00184     }
00185     
00186 }
00187 
00188 //===========================================================================
00189 int main(int varnum, char** vararg)  
00190 //===========================================================================
00191 {
00192     if (varnum == 1) {
00193         show_command_info();
00194         return -1;
00195     } 
00196     read_command_info(varnum, vararg);
00197     cout << "Now running with the following options: " << endl;
00198     show_current_vars();
00199     
00200     // Setting global values necessary for the gauss function or LIC
00201     L = 2 * sqrt(DT); // // parametric length for LIC 
00202     C = double(1) / sqrt(4 * PI * DT);
00203     D = double(1) / (4 * DT);
00204 
00205     clock_t start_time = clock();
00206     // loading source image
00207     Image<double> img;
00208     if (refers_to_stack(vararg[1])) {
00209         cout << "Reading 3D image stack...";
00210         ifstream is(vararg[1]);
00211         if (!is) {
00212             cerr << "Could not open file " << vararg[1] << endl;
00213             return 1;
00214         }
00215         img.read(is);
00216         cout << "Finished!" << endl;
00217     } else {
00218         cout << "Image is 2D " << endl;
00219         load_image(vararg[1], img, false);
00220     }
00221     permanent_display(img);
00222 
00223     const int X = img.dimx();
00224     const int Y = img.dimy();
00225     const int Z = img.dimz();
00226     const bool three_dimensional = Z > 1; 
00227     const int tensor_components = three_dimensional ? 6 : 3;
00228     const int vector_components = three_dimensional ? 4 : 3;
00229 
00230     Image<double> target(img, false); // no copying of contents
00231     target = 0;
00232 
00233     cout << "Allocating memory.." << endl;
00234     Image<double> G(X, Y, Z, tensor_components); // structure tensor
00235     Image<double> T(X, Y, Z, tensor_components); // smoothing tensor
00236     Image<double> W(X, Y, Z, vector_components); // smoothing vector field
00237     Image<double> img_blurred(img, false);
00238     cout << "Finished allocating memory" << endl;
00239     const double norm_fac = 
00240         three_dimensional ? double(1) / (DIV_THETA * DIV_PHI) : double(1) / DIV_THETA;
00241 
00242     for (int tstep = 0; tstep < NUM_TIMESTEPS; ++tstep) {
00243         img_blurred = img;
00244         cout << "Bluring image" << endl;
00245         blur_image(img_blurred, ALPHA);
00246         cout << "Rescaling image" << endl;
00247         rescale(img_blurred, 0, 255);
00248         //permanent_display(img_blurred); //@@
00249 
00250         if (three_dimensional) {
00251             cout << "Computing structure tensor" << endl;
00252             compute_structure_tensor_3D(img_blurred, G); 
00253             cout << "Bluring structure tensor" << endl;
00254             blur_image(G, SIGMA); 
00255             
00256             //permanent_display(G); //@@
00257             cout << "Computing smoothing geometry " << endl;
00258             compute_smoothing_geometry_3D(G, P1, P2, P3, T, true);
00259             //permanent_display(T);
00260             // decomposing T into a sum of vectors and carry out smoothing
00261 
00262             
00263             for (int phistep = 0; phistep < DIV_PHI; ++phistep) {
00264                 for (int thetastep = 0; thetastep < DIV_THETA; ++thetastep) {
00265                     const double phi = phistep * DPHI - PI/2;
00266                     const double theta = thetastep * DTHETA;
00267                     make_vector_field_3D(phi, theta, T, W);
00268                     
00269                     // line integral convolution
00270                     cout << "Convoluting with PHI = " << phi << " and THETA = " << theta << endl;
00271                     LIC_3D_FS(img, W, target, &gauss, DL, L);
00272                 }
00273             }
00274             // normalize target
00275             target *= norm_fac;
00276         } else {
00277 
00278             // 2D case
00279             compute_structure_tensor_2D(img_blurred, G);       
00280             blur_image(G, SIGMA);
00281             compute_smoothing_geometry_2D(G, P1, P2, T, true); 
00282             // decomposing T into a sum of vectors and carry out smoothing
00283             for (int a = 0; a < DIV_THETA; ++a) {
00284                 const double angle = a * DTHETA;
00285                 make_vector_field_2D(angle, T, W);
00286                 
00287                 // line integral convolution
00288                 LIC_2D_FS(img, W, target, &gauss, DL, L);
00289             }
00290             target *= norm_fac;
00291         }
00292         // swap images
00293         target.swap(img);
00294     }
00295     clock_t end_time = clock();
00296     //permanent_display(img);
00297     display_image(img);
00298     if (three_dimensional) {
00299         ofstream os(SAVED_3D_FILE);
00300         if (!os) {
00301             cerr << "Warning: not able to save 3D result because unable to open file." << endl;
00302         } else {
00303             img.write(os);
00304             os.close();
00305         }
00306     }
00307     cout << "Total CPU time was: " << double(end_time - start_time) / 1000 << " millisecs." << endl;
00308     return 1;
00309 };
00310 
00311 //===========================================================================
00312 void make_vector_field_3D(double phi, double theta, const Image<double>& tensor, Image<double>& vec)
00313 //===========================================================================
00314 {
00315     const double POLE_CORRECTION_FACTOR = sqrt(0.5);
00316     const double TINY = numeric_limits<double>::epsilon();
00317     assert(tensor.numChannels() == 6);
00318     const int X = tensor.dimx();
00319     const int Y = tensor.dimy();
00320     const int Z = tensor.dimz();
00321     const double v_x = cos(phi) * cos(theta);
00322     const double v_y = cos(phi) * sin(theta);
00323     const double v_z = POLE_CORRECTION_FACTOR * sin(phi);
00324     vec.resize(X, Y, Z, 4);
00325     for (int z = 0; z < Z; ++z) {
00326         for (int y = 0; y < Y; ++y) {
00327             for (int x = 0; x < X; ++x) {
00328                 const double txx = tensor(x, y, z, 0);
00329                 const double txy = tensor(x, y, z, 1);
00330                 const double tyy = tensor(x, y, z, 2);
00331                 const double txz = tensor(x, y, z, 3);
00332                 const double tyz = tensor(x, y, z, 4);
00333                 const double tzz = tensor(x, y, z, 5);
00334 
00335                 const double vx = txx * v_x + txy * v_y + txz * v_z;
00336                 const double vy = txy * v_x + tyy * v_y + tyz * v_z;
00337                 const double vz = txz * v_x + tyz * v_y + tzz * v_z; 
00338                 const double norm = sqrt(vx * vx + vy * vy + vz * vz);
00339                 const double norm_inv = (norm > TINY) ? double(1) / norm : 0;
00340                 vec(x, y, z, 0) = vx * norm_inv;
00341                 vec(x, y, z, 1) = vy * norm_inv;
00342                 vec(x, y, z, 2) = vz * norm_inv;
00343                 vec(x, y, z, 3) = norm;
00344 
00345                 assert(vec(x, y, z, 0) <= 1 && vec(x, y, z, 0) >= -1);
00346                 assert(vec(x, y, z, 1) <= 1 && vec(x, y, z, 1) >= -1);
00347                 assert(vec(x, y, z, 2) <= 1 && vec(x, y, z, 2) >= -1);
00348             }
00349         }
00350     }
00351 }
00352 
00353 //===========================================================================
00354 void make_vector_field_2D(double theta, const Image<double>& tensor, Image<double>& vec)
00355 //===========================================================================
00356 {
00357     assert(tensor.dimz() == 1 && tensor.numChannels() == 3);
00358     const int X = tensor.dimx();
00359     const int Y = tensor.dimy();
00360     const double sin_theta = sin(theta);
00361     const double cos_theta = cos(theta);
00362 
00363     vec.resize(X, Y, 1, 3);
00364 
00365     for (int y = 0; y < Y; ++y) {
00366         for (int x = 0; x < X; ++x) {
00367             const double a = tensor(x, y, 0, 0);
00368             const double b = tensor(x, y, 0, 1);
00369             const double c = tensor(x, y, 0, 2);
00370             const double vx = a * cos_theta + b * sin_theta;
00371             const double vy = b * cos_theta + c * sin_theta;
00372             const double norm = sqrt(vx*vx + vy * vy);
00373             const double norm_inv = double(1) / norm;
00374             vec(x, y, 0, 0) = vx * norm_inv;
00375             vec(x, y, 0, 1) = vy * norm_inv;
00376             vec(x, y, 0, 2) = norm;
00377         }
00378     }
00379 }
00380 
00381 
00382 //===========================================================================
00383 void show_command_info()
00384 //===========================================================================
00385 {
00386     cerr << "Usage: greycstoration2D <image> <option(s)>" << endl;
00387     cerr << "Where options are: " << endl;
00388     cerr << "-DT <timestep value (pos. double)>  -- default: " << DT << endl;
00389     cerr << "-ALPHA <smooth value(pos. double)>" << endl;
00390     cerr << "       -> how much to smooth the image prior to computing" << endl;
00391     cerr << "          the structure tensor G.   -- default: " << ALPHA << endl;
00392     cerr << "-SIGMA <smooth value (pos.double)>" << endl;
00393     cerr << "       -> how much to smooth the structure tensor G prior" << endl;
00394     cerr << "          to line integral convolution." << endl;
00395     cerr << "                                    -- default: " << SIGMA << endl;
00396     cerr << "-TIMESTEPS <positive integer>" << endl;
00397     cerr << "       -> how many timesteps (of length DT) that should be " << endl;
00398     cerr << "          computed.                 -- default: " << NUM_TIMESTEPS << endl;
00399     cerr << "-P1 <fac 1 (pos. double)> " << endl;
00400     cerr << "       -> specify how to smooth along the main smoothing direction." << endl;
00401     cerr << "          (approx. along isophote).  Higher values yield less" << endl;
00402     cerr << "          smoothing.                -- default: " << P1 << endl;
00403     cerr << "-P2 <fac 2 (pos. double)> " << endl;
00404     cerr << "       -> specify how to smooth along the minor smoothing direction. " << endl;
00405     cerr << "          (approx. along image gradient).  Higher values yield less" << endl;
00406     cerr << "          smoothing.  Should be higher than P1." << endl;
00407     cerr << "                                    -- default: " << P2 << endl;
00408     cerr << "-P3 <fac 3 (pos. double)> " << endl;
00409     cerr << "       -> specify how to smooth along the minor smoothing direction (3D). " << endl;
00410     cerr << "          Higher values yield less smoothing.  Should be higher than P2." << endl;
00411     cerr << "                                    -- default: " << P3 << endl;
00412     cerr << endl;
00413     cerr << "The <image> argument can be the name of a picture in any of the most common ";
00414     cerr << "formats (jpeg, tiff, png, etc.).  In that case, the 2D image will be read ";
00415     cerr << "and treated by the algorithm in a 2D way.  You can also give the algorithm ";
00416     cerr << "a stack of images, and it will process this stack as one 3D image.  A ";
00417     cerr << "stack file has 'stack' as its suffix, and can be made using the ";
00418     cerr << "'generate_stack' utility program (run it to get an explanation of " << endl;
00419     cerr << "its use.  In case a 3D stack is to be processed, the result is ALWAYS saved ";
00420     cerr << "to the file \"" << SAVED_3D_FILE << "\"." << endl;
00421 }
00422 
00423 //===========================================================================
00424 void read_command_info(int varnum, char** vararg)
00425 //===========================================================================
00426 {
00427     for (int i = 2; i != varnum; i+=2) {
00428         string arg(vararg[i]);
00429         if (arg=="-DT") {
00430             DT = atof(vararg[i+1]);
00431         } else if (arg=="-ALPHA") {
00432             ALPHA = atof(vararg[i+1]);
00433         } else if (arg=="-SIGMA") { 
00434             SIGMA = atof(vararg[i+1]);
00435         } else if (arg=="-TIMESTEPS") {
00436             NUM_TIMESTEPS = atoi(vararg[i+1]);
00437         } else if (arg=="-P1") {
00438             P1 = atof(vararg[i+1]);
00439         } else if (arg=="-P2") {
00440             P2 = atof(vararg[i+1]);
00441         } else if (arg=="-P3") {
00442             P3 = atof(vararg[i+1]);
00443         } else {
00444             cerr << "Unrecognized option: " << arg << endl;
00445             exit(-1);
00446         }
00447     }
00448 }
00449 
00450 //===========================================================================
00451 void show_current_vars()
00452 //===========================================================================
00453 {
00454     cout << "--------------------------" << endl;
00455     cout << "DT:             " << DT << endl;
00456     cout << "ALPHA:          " << ALPHA << endl;
00457     cout << "SIGMA:          " << SIGMA << endl;
00458     cout << "NUM_TIMESTEPS:  " << NUM_TIMESTEPS << endl;
00459     cout << "P1:             " << P1 << endl;
00460     cout << "P2:             " << P2 << endl;
00461     cout << "P3:             " << P3 << endl;
00462     cout << "--------------------------" << endl;
00463 }

Generated on Tue Nov 28 18:35:47 2006 for lsseg by  doxygen 1.4.7