Jerome Piovano

Research in Medical Imaging and Computer Vision

/home/jpiovano/src/Odyssee++/trunk/Libs/LevelSet/src/DericheFilter.h

Go to the documentation of this file.
00001 
00008 #ifndef DERICHEFILTER_H
00009 #define DERICHEFILTER_H
00010 
00011 #ifdef _USE_INTEL_COMPILER
00012 #include <omp.h>
00013 #endif
00014 
00015 #include <Image.H>
00016 
00017 using namespace Images;
00018 
00019 namespace Images {
00020 
00042                 template<unsigned DIM, typename Pixel = float>
00043                 class DericheFilter
00044                 {
00045                 public:
00046 
00047                         typedef          BaseImage<DIM, Pixel>             Image;
00048                         typedef typename Image::Index                      Index;
00049                         typedef          BaseImage<DIM, float>             ImageVariance;
00050                         typedef          blitz::RectDomain<DIM>            RectDomain;
00051 
00053 
00055 
00057                         DericheFilter(float _sigma,               
00058                                       int   _order = 0,           
00059                                       bool  _border_cond = true   
00060                                       );
00061 
00063                         DericheFilter(float _sigma[DIM],          
00064                                       int   _order = 0,           
00065                                       bool  _border_cond = true   
00066                                       );
00067 
00069                         DericheFilter(ImageVariance& _sigma,               
00070                                       int            _order = 0,           
00071                                       bool           _border_cond = true   
00072                                       );
00073 
00075                         ~DericheFilter();
00076 
00078 
00080 
00082                         void filter(Image& image);
00084                         void filter_axis(Image& image, const int axis);
00085 
00087 
00089 
00091                         void set_filter_type(int _filter_type);
00093                         void set_order(int _order);
00095                         void set_border_cond(bool _border_cond);
00096 
00098                         void set_isotropic_sigma(float _sigma);
00100                         void set_anisotropic_sigma(float _sigma[DIM]);
00102                         void set_image_sigma(const ImageVariance& _sigma);
00103 
00104                 protected:
00105 
00107 
00109 
00111                         void _init_coefs();     
00113                         void _coefs_sigma(float sigma, float coefs[6],  float border_coefs[4]);
00114 
00116                         void _deriche_map(Image line, const int axis, Pixel* tmp_buf, Index lbound, Index ubound);
00117 
00118 
00120 
00122 
00123                         int              m_filter_type;                   
00124                         int              m_order;                         
00125                         bool             m_border_cond;                   
00126 
00127                         float            m_sigma[DIM];                    
00128                         ImageVariance *  m_sigma_image;                   
00129 
00130                         float            m_coefs[6*DIM];                  
00131                         ImageVariance *  m_variant_coefs[6];              
00132 
00133                         float            m_border_coefs[4*DIM];           
00134 
00136 
00137                 };
00138 
00139 
00144 
00145                 // Constructors - Destructor
00146 
00147 
00148                 template<unsigned DIM, typename Pixel>
00149                         DericheFilter<DIM, Pixel>::DericheFilter(float _sigma, int _order, bool _border_cond)
00150                         :m_filter_type(0), m_order(_order), m_sigma_image(NULL), m_border_cond(_border_cond)
00151                 {
00152                         for (int i=0 ; i<DIM; i++) 
00153                                 m_sigma[i] = _sigma;
00154 
00155                         for (int i=0 ; i<6; i++) 
00156                                 m_variant_coefs[i] = NULL;
00157 
00158                         _init_coefs();
00159                 }
00160 
00161                 template<unsigned DIM, typename Pixel>
00162                         DericheFilter<DIM, Pixel>::DericheFilter(float _sigma[DIM], int _order, bool _border_cond)
00163                         :m_filter_type(1), m_order(_order), m_sigma_image(NULL), m_border_cond(_border_cond)
00164                 { 
00165                         for (int i=0 ; i<DIM; i++) 
00166                                 m_sigma[i] = _sigma[i];
00167 
00168                         for (int i=0 ; i<6; i++) 
00169                                 m_variant_coefs[i] = NULL;
00170 
00171                         _init_coefs();
00172                 }
00173 
00174                 template<unsigned DIM, typename Pixel>
00175                         DericheFilter<DIM, Pixel>::DericheFilter(ImageVariance& _sigma, int _order, bool _border_cond)
00176                         :m_filter_type(2), m_order(_order), m_sigma_image(&_sigma), m_border_cond(_border_cond)
00177                 {
00178                         for (int i=0 ; i<DIM; i++)
00179                                 m_sigma[i] = 0.0;
00180 
00181                         for (int i=0 ; i<6; i++) 
00182                                 m_variant_coefs[i] = NULL;
00183 
00184                         _init_coefs();
00185                 }
00186 
00187                 template<unsigned DIM, typename Pixel>
00188                         DericheFilter<DIM, Pixel>::~DericheFilter()
00189                 {
00190                         for (int i=0 ; i<6; i++)
00191                                 if (m_variant_coefs[i] != NULL)
00192                                          delete m_variant_coefs[i];
00193                 }
00194 
00195 
00197                 // Main Method
00198 
00199 
00200                 template<unsigned DIM, typename Pixel>
00201                         void DericheFilter<DIM, Pixel>::filter(Image& image)
00202                 {
00203                         for (int i=1 ; i<=DIM ; i++)
00204                                 filter_axis(image, i);
00205                 }
00206 
00207                 template<unsigned DIM, typename Pixel>
00208                         void DericheFilter<DIM, Pixel>::filter_axis(Image& image, const int axis)
00209                 {
00210                         // get the first slice in the given axis
00211                         Index tl = image.lbound();
00212                         Index br = image.ubound(); 
00213                         tl(axis) = 0;
00214                         br(axis) = 0;
00215                                 
00216                         blitz::RectDomain<DIM> rect_domain(tl, br);
00217                         Image slice = image(rect_domain);
00218                         int ubound = image.ubound(axis-1);
00219 
00220                 #if 0   
00221 
00222                         Pixel* tmp_buf = new Pixel[image.extent(axis-1)];
00223                 
00224                         // on each pixel of the slice, get its "perpendicular line" in the axis direction, and make a deriche filter on it
00225                         for (typename Image::template iterator<domain> i=slice.begin() ; i!=slice.end() ; ++i){
00226                                 rect_domain.lbound() = i.position();
00227                                 rect_domain.ubound() = i.position();
00228                                 rect_domain.ubound(axis-1) = ubound;
00229 
00230                                 _deriche_map(image(rect_domain), axis, tmp_buf, rect_domain.lbound(), rect_domain.ubound());
00231                         }
00232 
00233                         delete[] tmp_buf;
00234 
00235                 #else   
00236 
00237                         Index tmp[slice.size()];
00238                         int i = 0;
00239                         for (typename Image::template iterator<domain> it=slice.begin() ; it!=slice.end() ; ++it)
00240                                 tmp[i++] = it.position();
00241 
00242                         #pragma omp parallel 
00243                         {
00244                         // ATTENTION un Ybuf par thread.
00245                         Pixel* tmp_buf = new Pixel[image.extent(axis-1)];
00246                         #pragma omp for
00247                         for (int i = 0 ; i < slice.size() ; i++){
00248                                 blitz::RectDomain<DIM> rect_domain(tmp[i],tmp[i]);
00249                                 rect_domain.ubound(axis-1) = ubound;
00250                                 _deriche_map(image(rect_domain), axis, tmp_buf, rect_domain.lbound(), rect_domain.ubound());
00251                         }
00252                         delete[] tmp_buf;
00253                         }
00254                 #endif
00255 
00256                 }
00257 
00258 
00260                 // Modify/Access member data 
00261 
00262 
00263                 template<unsigned DIM, typename Pixel>
00264                         void DericheFilter<DIM, Pixel>::set_filter_type(int _filter_type)
00265                 {
00266                         m_filter_type = _filter_type;
00267                 }
00268 
00269                 template<unsigned DIM, typename Pixel>
00270                         void DericheFilter<DIM, Pixel>::set_order(int _order)
00271                 {
00272                         m_order = _order;
00273                 }
00274 
00275                 template<unsigned DIM, typename Pixel>
00276                         void DericheFilter<DIM, Pixel>::set_border_cond(bool _border_cond)
00277                 {
00278                         m_border_cond = _border_cond;
00279                 }       
00280 
00281                 template<unsigned DIM, typename Pixel>
00282                         void DericheFilter<DIM, Pixel>::set_isotropic_sigma(float _sigma)
00283                 {
00284                         m_filter_type = 0;
00285                         for (int i=0 ; i<DIM; i++)
00286                                 m_sigma[i] = _sigma;
00287                         _init_coefs();
00288                 }
00289 
00290                 template<unsigned DIM, typename Pixel>
00291                         void DericheFilter<DIM, Pixel>::set_anisotropic_sigma(float _sigma[DIM])
00292                 {
00293                         m_filter_type = 1;
00294                         for (int i=0 ; i<DIM; i++)
00295                                 m_sigma[i] = _sigma[i];
00296                         _init_coefs();
00297                 }
00298 
00299                 template<unsigned DIM, typename Pixel>
00300                         void DericheFilter<DIM, Pixel>::set_image_sigma(const ImageVariance& _sigma)
00301                 {
00302                         m_filter_type = 2;
00303                         m_sigma_image = &_sigma;
00304                         _init_coefs();
00305                 }
00306 
00307 
00309                 // Internal method 
00310 
00311 
00312                 template<unsigned DIM, typename Pixel>
00313                         void DericheFilter<DIM, Pixel>::_init_coefs()
00314                 {
00315 
00316                         float coefs[6];
00317                         float border_coefs[4];
00318 
00319                         switch(m_filter_type){
00320 
00321                                 case 0 :                                     // isotropic filter
00322                                         _coefs_sigma(m_sigma[0], coefs, border_coefs);
00323                                         for (int i = 0 ; i < 6*DIM ; i++)
00324                                                 m_coefs[i] = coefs[i%6];
00325                                         for (int i = 0 ; i < 4*DIM ; i++)
00326                                                 m_border_coefs[i] = border_coefs[i%4];
00327                                         break;
00328 
00329                                 case 1 :                                     // anisotropic filter
00330                                         for (int i = 0 ; i < DIM ; i++){
00331                                                 _coefs_sigma(m_sigma[i], coefs, border_coefs);
00332                                                 for (int j = 0 ; j < 6 ; j++)
00333                                                         m_coefs[i*6 + j] = coefs[j];
00334                                                 for (int j = 0 ; j < 4 ; j++)
00335                                                         m_border_coefs[i*4 + j] = border_coefs[j];
00336                                         }
00337                                         break;
00338 
00339                                 case 2 :                                     // space variant filter
00340                                         for (int i=0 ; i<6 ; i++){
00341                                                 if (m_variant_coefs[i] != NULL) delete m_variant_coefs[i];
00342                                                 m_variant_coefs[i] = new ImageVariance(m_sigma_image->shape());
00343                                         }
00344                                         for (typename ImageVariance::template iterator<domain> i=m_sigma_image->begin() ; i!=m_sigma_image->end() ; ++i ){
00345                                                 _coefs_sigma((*m_sigma_image)(i), coefs, border_coefs);
00346                                                 for (int j = 0 ; j < 6 ; j++)
00347                                                         (*m_variant_coefs[j])(i) = coefs[j];    
00348                                         }
00349                                         break;
00350                         }
00351                 }
00352 
00353                 template<unsigned DIM, typename Pixel>
00354                         void DericheFilter<DIM, Pixel>::_coefs_sigma(float sigma, float coefs[6],  float border_coefs[4])
00355                 {
00356                 
00357                         float a1,a2,a3,a4,b1,b2;         // coefs
00358                         float parity, g0, sumg1, sumg0;  // border coefs
00359 
00360                         // by default, dirichlet border condition
00361                         g0 = sumg0 = sumg1 = 0;
00362 
00363                         // precomputation of some values
00364                         const float alpha=sigma>0?1.695f/sigma:0;
00365                         const float ea=(float)exp(alpha);
00366                         const float ema=(float)exp(-alpha);
00367                         const float em2a=ema*ema;
00368 
00369                         // b1, b2 do not depend on the order of derivation
00370                         b1=2*ema;
00371                         b2=-em2a;
00372 
00373                         float ek,ekn;
00374 
00375                         // a1, a2, a3, a4 depend on the order of derivation
00376                         switch(m_order)
00377                         {
00378                                 case 1:                 // first derivative
00379                                         ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema);
00380                                         a1 = 0;
00381                                         a2 = ek*ema;
00382                                         a3 = -ek*ema;
00383                                         a4 = 0;
00384                                         parity = 1;
00385                                         if (m_border_cond) { 
00386                                                 sumg1 = (ek*ea)/((ea-1)*(ea-1));
00387                                                 g0    = 0;
00388                                                 sumg0 = g0+sumg1; 
00389                                         }
00390                                         break;
00391                                 case 2:               // second derivative
00392                                         ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) );
00393                                         ek = -(em2a-1)/(2*alpha*ema);
00394                                         a1 = ekn;
00395                                         a2 = -ekn*(1+ek*alpha)*ema;
00396                                         a3 = ekn*(1-ek*alpha)*ema;
00397                                         a4 = -ekn*em2a;
00398                                         parity = -1;
00399                                         if (m_border_cond) {
00400                                                 sumg1 = ekn/2;
00401                                                 g0    = ekn;
00402                                                 sumg0 = g0+sumg1;
00403                                         }
00404                                         break;
00405                                 default:              // smoothing
00406                                         ek = (1-ema)*(1-ema) / (1+2*alpha*ema - em2a);
00407                                         a1 = ek;
00408                                         a2 = ek*ema*(alpha-1);
00409                                         a3 = ek*ema*(alpha+1);
00410                                         a4 = -ek*em2a;
00411                                         parity = 1;
00412                                         if (m_border_cond) {
00413                                                 sumg1 = ek*(alpha*ea+ea-1)/((ea-1)*(ea-1));
00414                                                 g0    = ek;
00415                                                 sumg0 = g0+sumg1;
00416                                         }
00417                                         break;
00418                         }
00419 
00420                         coefs[0] = a1;
00421                         coefs[1] = a2;
00422                         coefs[2] = a3;
00423                         coefs[3] = a4;
00424                         coefs[4] = b1;
00425                         coefs[5] = b2;
00426 
00427                         border_coefs[0] = parity;
00428                         border_coefs[1] = g0;
00429                         border_coefs[2] = sumg1;
00430                         border_coefs[3] = sumg0;
00431                 }
00432 
00433                 template<unsigned DIM, typename Pixel>
00434                         void DericheFilter<DIM, Pixel>::_deriche_map(Image line, const int axis, Pixel* temp_buf, Index lbound, Index ubound)
00435                 {
00436                         float b1, b2, a1, a2, a3, a4;    // coefs
00437                         float parity, g0, sumg1, sumg0;  // border coefs
00438 
00439                         if (m_filter_type != 2){
00440                                 a1 = m_coefs[(axis-1)*6];
00441                                 a2 = m_coefs[(axis-1)*6 + 1];
00442                                 a3 = m_coefs[(axis-1)*6 + 2];
00443                                 a4 = m_coefs[(axis-1)*6 + 3];
00444                                 b1 = m_coefs[(axis-1)*6 + 4];
00445                                 b2 = m_coefs[(axis-1)*6 + 5];
00446 
00447                                 parity = m_border_coefs[(axis-1)*4];
00448                                 g0     = m_border_coefs[(axis-1)*4 + 1];
00449                                 sumg1  = m_border_coefs[(axis-1)*4 + 2];
00450                                 sumg0  = m_border_coefs[(axis-1)*4 + 3];
00451                         }
00452                         
00453                         typename Image::template iterator<domain> i = line.begin();
00454                         Pixel Y0, I0, Y1, I1, Y2, I2;
00455 
00456                         // forward passing border condition
00457 
00458                         if (m_filter_type != 2){ 
00459                                 I1 = line(i); ++i;
00460                                 I2 = line(i); ++i;
00461                                 Y2 = *(temp_buf++) = sumg0*I2;
00462                                 Y1 = *(temp_buf++) = g0*I1 + sumg1*I2;
00463                         }
00464                         else{
00465                                 I1 = line(i);
00466                                 I2 = I1;
00467                                 Y1 = I1/2.0;
00468                                 Y2 = I1/2.0;
00469                         }
00470                         
00471                         // forward passing
00472 
00473                         for (; i != line.end() ; ++i){  
00474                                 if (m_filter_type == 2){
00475                                         a1 = (*m_variant_coefs[0])(i.position() + lbound);
00476                                         a2 = (*m_variant_coefs[1])(i.position() + lbound);
00477                                         b1 = (*m_variant_coefs[4])(i.position() + lbound);
00478                                         b2 = (*m_variant_coefs[5])(i.position() + lbound);
00479                                 }
00480                                 I1 = line(i);
00481                                 Y0 = *(temp_buf++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2; 
00482                                 I2=I1;
00483                                 Y2=Y1;
00484                                 Y1=Y0;
00485                         }
00486 
00487                         // backward passing border condition
00488                         
00489                         line.reverseSelf(axis-1);
00490                         i = line.begin();
00491                         
00492                         if (m_filter_type != 2){ 
00493                                 I2 = line(i);
00494                                 Y2 = Y1 = parity*sumg1*I2;
00495                                 line(i) = *(--temp_buf)+Y2; ++i;
00496                                 I0 = line(i);
00497                                 line(i) = *(--temp_buf)+Y1; ++i;
00498                         }
00499                         else{
00500                                 I1 = line(i);
00501                                 I2 = I1;
00502                                 Y1 = I1/2.0;
00503                                 Y2 = I1/2.0;
00504                         }
00505                         
00506                         // backward passing
00507                         
00508                         for (; i != line.end() ; ++i){
00509                                 if (m_filter_type == 2){
00510                                         a3 = (*m_variant_coefs[2])(ubound - i.position());
00511                                         a4 = (*m_variant_coefs[3])(ubound - i.position());
00512                                         b1 = (*m_variant_coefs[4])(ubound - i.position());
00513                                         b2 = (*m_variant_coefs[5])(ubound - i.position());
00514                                 }
00515                                 Y0= a3*I1 + a4*I2 + b1*Y1 + b2*Y2;
00516                                 I2=I1;
00517                                 Y2=Y1;
00518                                 Y1=Y0;
00519                                 I1=line(i);
00520                                 line(i)= *(--temp_buf) + Y0;  //stocking the new results!
00521                         }
00522                 }
00523 }
00524 
00525 #endif // DERICHEFILTER_H

For further information, please contact Jerome Piovano - Last update 2008-02-08