PTdecode/CImg-1.3.0/plugins/greycstoration.h

Wed, 05 Aug 2009 17:32:05 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 05 Aug 2009 17:32:05 +0100
changeset 18
fd1c6f6066da
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

updated README

     1 /*
     2   #
     3   #  File        : greycstoration.h
     4   #                ( C++ header file - CImg plug-in )
     5   #
     6   #  Description : GREYCstoration plug-in allowing easy integration in
     7   #                third parties softwares.
     8   #                ( http://www.greyc.ensicaen.fr/~dtschump/greycstoration/ )
     9   #                This file is a part of the CImg Library project.
    10   #                ( http://cimg.sourceforge.net )
    11   #
    12   #  THIS PLUG-IN IS INTENDED FOR DEVELOPERS ONLY. IT EASES THE INTEGRATION ALGORITHM IN
    13   #  THIRD PARTIES SOFTWARES. IF YOU ARE A USER OF GREYCSTORATION, PLEASE LOOK
    14   #  AT THE FILE 'greycstoration.cpp' WHICH IS THE SOURCE OF THE COMPLETE
    15   #  COMMAND LINE GREYCSTORATION TOOL.
    16   #
    17   #  Copyright   : David Tschumperle
    18   #                ( http://www.greyc.ensicaen.fr/~dtschump/ )
    19   #
    20   #  License     : CeCILL v2.0
    21   #                ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    22   #
    23   #  This software is governed by the CeCILL  license under French law and
    24   #  abiding by the rules of distribution of free software.  You can  use,
    25   #  modify and/ or redistribute the software under the terms of the CeCILL
    26   #  license as circulated by CEA, CNRS and INRIA at the following URL
    27   #  "http://www.cecill.info".
    28   #
    29   #  As a counterpart to the access to the source code and  rights to copy,
    30   #  modify and redistribute granted by the license, users are provided only
    31   #  with a limited warranty  and the software's author,  the holder of the
    32   #  economic rights,  and the successive licensors  have only  limited
    33   #  liability.
    34   #
    35   #  In this respect, the user's attention is drawn to the risks associated
    36   #  with loading,  using,  modifying and/or developing or reproducing the
    37   #  software by the user in light of its specific status of free software,
    38   #  that may mean  that it is complicated to manipulate,  and  that  also
    39   #  therefore means  that it is reserved for developers  and  experienced
    40   #  professionals having in-depth computer knowledge. Users are therefore
    41   #  encouraged to load and test the software's suitability as regards their
    42   #  requirements in conditions enabling the security of their systems and/or
    43   #  data to be ensured and,  more generally, to use and operate it in the
    44   #  same conditions as regards security.
    45   #
    46   #  The fact that you are presently reading this means that you have had
    47   #  knowledge of the CeCILL license and that you accept its terms.
    48   #
    49 */
    51 #ifndef cimg_plugin_greycstoration
    52 #define cimg_plugin_greycstoration
    54 //------------------------------------------------------------------------------
    55 // GREYCstoration parameter structure, storing important informations about
    56 // algorithm parameters and computing threads.
    57 // ** This structure has not to be manipulated by the API user, so please just
    58 // ignore it if you want to **
    59 //-------------------------------------------------------------------------------
    60 struct _greycstoration_params {
    62   // Tell if the patch-based algorithm is selected
    63   bool patch_based;
    65   // Parameters specific to the non-patch regularization algorithm
    66   float amplitude;
    67   float sharpness;
    68   float anisotropy;
    69   float alpha;
    70   float sigma;
    71   float gfact;
    72   float dl;
    73   float da;
    74   float gauss_prec;
    75   unsigned int interpolation;
    77   // Parameters specific to the patch-based regularization algorithm
    78   unsigned int patch_size;
    79   float sigma_s;
    80   float sigma_p;
    81   unsigned int lookup_size;
    83   // Non-specific parameters of the algorithms.
    84   CImg<T> *source;
    85   const CImg<unsigned char> *mask;
    86   CImg<T> *temporary;
    87   unsigned long *counter;
    88   unsigned int tile;
    89   unsigned int tile_border;
    90   unsigned int thread;
    91   unsigned int nb_threads;
    92   bool fast_approx;
    93   bool is_running;
    94   bool *stop_request;
    95 #if cimg_OS==1 && defined(_PTHREAD_H)
    96   pthread_mutex_t
    97   *mutex;
    98 #elif cimg_OS==2
    99   HANDLE mutex;
   100 #else
   101   void *mutex;
   102 #endif
   104   // Default constructor
   105   _greycstoration_params():patch_based(false),amplitude(0),sharpness(0),anisotropy(0),alpha(0),sigma(0),gfact(1),
   106        dl(0),da(0),gauss_prec(0),interpolation(0),patch_size(0),
   107        sigma_s(0),sigma_p(0),lookup_size(0),source(0),mask(0),temporary(0),counter(0),tile(0),
   108        tile_border(0),thread(0),nb_threads(0),fast_approx(false),is_running(false), stop_request(0), mutex(0) {}
   109 };
   111 _greycstoration_params greycstoration_params[16];
   113 //----------------------------------------------------------
   114 // Public functions of the GREYCstoration API.
   115 // Use the functions below for integrating GREYCstoration
   116 // in your own C++ code.
   117 //----------------------------------------------------------
   119 //! Test if GREYCstoration threads are still running.
   120 bool greycstoration_is_running() const {
   121   return greycstoration_params->is_running;
   122 }
   124 //! Force the GREYCstoration threads to stop.
   125 CImg& greycstoration_stop() {
   126   if (greycstoration_is_running()) {
   127     *(greycstoration_params->stop_request) = true;
   128     while (greycstoration_params->is_running) cimg::wait(50);
   129   }
   130   return *this;
   131 }
   133 //! Return the GREYCstoration progress bar indice (between 0 and 100).
   134 float greycstoration_progress() const {
   135   if (!greycstoration_is_running()) return 0.0f;
   136   const unsigned long counter = greycstoration_params->counter?*(greycstoration_params->counter):0;
   137   const float
   138     da = greycstoration_params->da,
   139     factor = greycstoration_params->patch_based?1:(1+360/da);
   140   float maxcounter = 0;
   141   if (greycstoration_params->tile==0) maxcounter = width*height*depth*factor;
   142   else {
   143     const unsigned int
   144       t = greycstoration_params->tile,
   145       b = greycstoration_params->tile_border,
   146       n = (1+(width-1)/t)*(1+(height-1)/t)*(1+(depth-1)/t);
   147     maxcounter = (width*height*depth + n*4*b*(b + t))*factor;
   148   }
   149   return cimg::min(counter*99.9f/maxcounter,99.9f);
   150 }
   152 //! Run the non-patch version of the GREYCstoration algorithm on the instance image, using a mask.
   153 CImg& greycstoration_run(const CImg<unsigned char>& mask,
   154                          const float amplitude=60, const float sharpness=0.7f, const float anisotropy=0.3f,
   155                          const float alpha=0.6f, const float sigma=1.1f, const float gfact=1.0f,
   156                          const float dl=0.8f, const float da=30.0f,
   157                          const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
   158                          const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1) {
   160   if (greycstoration_is_running())
   161     throw CImgInstanceException("CImg<T>::greycstoration_run() : A GREYCstoration thread is already running on"
   162                                 " the instance image (%u,%u,%u,%u,%p).",width,height,depth,dim,data);
   164   else {
   165     if (!mask.is_empty() && !mask.is_sameXY(*this))
   166       throw CImgArgumentException("CImg<%s>::greycstoration_run() : Given mask (%u,%u,%u,%u,%p) and instance image "
   167                                   "(%u,%u,%u,%u,%p) have different dimensions.",
   168                                   pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data,width,height,depth,dim,data);
   169     if (nb_threads>16) cimg::warn("CImg<%s>::greycstoration_run() : Multi-threading mode limited to 16 threads max.");
   170     const unsigned int
   171       ntile = (tile && (tile<width || tile<height || (depth>1 && tile<depth)))?tile:0,
   172 #if cimg_OS==1 && !defined(_PTHREAD_H)
   173       nthreads = 0;
   174 #else
   175     nthreads = ntile?cimg::min(nb_threads,16U):cimg::min(nb_threads,1U);
   176 #endif
   178     CImg<T> *const temporary = ntile?new CImg<T>(*this):0;
   179     unsigned long *const counter = new unsigned long;
   180     *counter = 0;
   181     bool *const stop_request = new bool;
   182     *stop_request = false;
   184     for (unsigned int k=0; k<(nthreads?nthreads:1); k++) {
   185       greycstoration_params[k].patch_based = false;
   186       greycstoration_params[k].amplitude = amplitude;
   187       greycstoration_params[k].sharpness = sharpness;
   188       greycstoration_params[k].anisotropy = anisotropy;
   189       greycstoration_params[k].alpha = alpha;
   190       greycstoration_params[k].sigma = sigma;
   191       greycstoration_params[k].gfact = gfact;
   192       greycstoration_params[k].dl = dl;
   193       greycstoration_params[k].da = da;
   194       greycstoration_params[k].gauss_prec = gauss_prec;
   195       greycstoration_params[k].interpolation = interpolation;
   196       greycstoration_params[k].fast_approx = fast_approx;
   197       greycstoration_params[k].source = this;
   198       greycstoration_params[k].mask = &mask;
   199       greycstoration_params[k].temporary = temporary;
   200       greycstoration_params[k].counter = counter;
   201       greycstoration_params[k].tile = ntile;
   202       greycstoration_params[k].tile_border = tile_border;
   203       greycstoration_params[k].thread = k;
   204       greycstoration_params[k].nb_threads = nthreads;
   205       greycstoration_params[k].is_running = true;
   206       greycstoration_params[k].stop_request = stop_request;
   207       if (k) greycstoration_params[k].mutex = greycstoration_params[0].mutex;
   208       else greycstoration_mutex_create(greycstoration_params[0]);
   209     }
   210     if (nthreads) {  // Threaded version
   211 #if cimg_OS==1
   212 #ifdef _PTHREAD_H
   213       pthread_attr_t attr;
   214       pthread_attr_init(&attr);
   215       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   216       for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
   217         pthread_t thread;
   218         const int err = pthread_create(&thread, &attr, greycstoration_thread, (void*)(greycstoration_params+k));
   219         if (err) throw CImgException("CImg<%s>::greycstoration_run() : pthread_create returned error %d",
   220                                      pixel_type(), err);
   221       }
   222 #endif
   223 #elif cimg_OS==2
   224       for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
   225         unsigned long ThreadID = 0;
   226         CreateThread(0,0,greycstoration_thread,(void*)(greycstoration_params+k),0,&ThreadID);
   227       }
   228 #else
   229       throw CImgInstanceException("CImg<T>::greycstoration_run() : Threads are not supported, please define cimg_OS first.");
   230 #endif
   231     } else greycstoration_thread((void*)greycstoration_params); // Non-threaded version
   232   }
   233   return *this;
   234 }
   236 //! Run the non-patch version of the GREYCstoration algorithm on the instance image.
   237 CImg& greycstoration_run(const float amplitude=50, const float sharpness=0.7f, const float anisotropy=0.3f,
   238                          const float alpha=0.6f, const float sigma=1.1f, const float gfact=1.0f,
   239                          const float dl=0.8f, const float da=30.0f,
   240                          const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
   241                          const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1) {
   242   static const CImg<unsigned char> empty_mask;
   243   return greycstoration_run(empty_mask,amplitude,sharpness,anisotropy,alpha,sigma,gfact,dl,da,gauss_prec,
   244                             interpolation,fast_approx,tile,tile_border,nb_threads);
   245 }
   247 //! Run the patch-based version of the GREYCstoration algorithm on the instance image.
   248 CImg& greycstoration_patch_run(const unsigned int patch_size=5, const float sigma_p=10, const float sigma_s=100,
   249                                const unsigned int lookup_size=20, const bool fast_approx=true,
   250                                const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1) {
   252   static const CImg<unsigned char> empty_mask;
   253   if (greycstoration_is_running())
   254     throw CImgInstanceException("CImg<T>::greycstoration_run() : A GREYCstoration thread is already running on"
   255                                 " the instance image (%u,%u,%u,%u,%p).",width,height,depth,dim,data);
   257   else {
   258     if (nb_threads>16) cimg::warn("CImg<%s>::greycstoration_run() : Multi-threading mode limited to 16 threads max.");
   259     const unsigned int
   260       ntile = (tile && (tile<width || tile<height || (depth>1 && tile<depth)))?tile:0,
   261 #if cimg_OS==1 && !defined(_PTHREAD_H)
   262       nthreads = 0;
   263 #else
   264     nthreads = ntile?cimg::min(nb_threads,16U):cimg::min(nb_threads,1U);
   265 #endif
   267     CImg<T> *const temporary = ntile?new CImg<T>(*this):0;
   268     unsigned long *const counter = new unsigned long;
   269     *counter = 0;
   270     bool *const stop_request = new bool;
   271     *stop_request = false;
   273     for (unsigned int k=0; k<(nthreads?nthreads:1); k++) {
   274       greycstoration_params[k].patch_based = true;
   275       greycstoration_params[k].patch_size = patch_size;
   276       greycstoration_params[k].sigma_s = sigma_s;
   277       greycstoration_params[k].sigma_p = sigma_p;
   278       greycstoration_params[k].lookup_size = lookup_size;
   279       greycstoration_params[k].source = this;
   280       greycstoration_params[k].mask = &empty_mask;
   281       greycstoration_params[k].temporary = temporary;
   282       greycstoration_params[k].counter = counter;
   283       greycstoration_params[k].tile = ntile;
   284       greycstoration_params[k].tile_border = tile_border;
   285       greycstoration_params[k].thread = k;
   286       greycstoration_params[k].nb_threads = nthreads;
   287       greycstoration_params[k].fast_approx = fast_approx;
   288       greycstoration_params[k].is_running = true;
   289       greycstoration_params[k].stop_request = stop_request;
   290       if (k) greycstoration_params[k].mutex = greycstoration_params[0].mutex;
   291       else greycstoration_mutex_create(greycstoration_params[0]);
   292     }
   293     if (nthreads) {  // Threaded version
   294 #if cimg_OS==1
   295 #ifdef _PTHREAD_H
   296       pthread_attr_t attr;
   297       pthread_attr_init(&attr);
   298       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   299       for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
   300         pthread_t thread;
   301         const int err = pthread_create(&thread, &attr, greycstoration_thread, (void*)(greycstoration_params+k));
   302         if (err) throw CImgException("CImg<%s>::greycstoration_run() : pthread_create returned error %d",
   303                                      pixel_type(), err);
   304       }
   305 #endif
   306 #elif cimg_OS==2
   307       for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
   308         unsigned long ThreadID = 0;
   309         CreateThread(0,0,greycstoration_thread,(void*)(greycstoration_params+k),0,&ThreadID);
   310       }
   311 #else
   312       throw CImgInstanceException("CImg<T>::greycstoration_run() : Threads support have not been enabled in this version of GREYCstoration.");
   313 #endif
   314     } else greycstoration_thread((void*)greycstoration_params); // Non-threaded version
   315   }
   316   return *this;
   317 }
   319 //------------------------------------------------------------------------------
   320 // GREYCstoration private functions.
   321 // Should not be used directly by the API user.
   322 //-------------------------------------------------------------------------------
   324 static void greycstoration_mutex_create(_greycstoration_params &p) {
   325   if (p.nb_threads>1) {
   326 #if cimg_OS==1 && defined(_PTHREAD_H)
   327     p.mutex = new pthread_mutex_t;
   328     pthread_mutex_init(p.mutex,0);
   329 #elif cimg_OS==2
   330     p.mutex = CreateMutex(0,FALSE,0);
   331 #endif
   332   }
   333 }
   335 static void greycstoration_mutex_lock(_greycstoration_params &p) {
   336   if (p.nb_threads>1) {
   337 #if cimg_OS==1 && defined(_PTHREAD_H)
   338     if (p.mutex) pthread_mutex_lock(p.mutex);
   339 #elif cimg_OS==2
   340     WaitForSingleObject(p.mutex,INFINITE);
   341 #endif
   342   }
   343 }
   345 static void greycstoration_mutex_unlock(_greycstoration_params &p) {
   346   if (p.nb_threads>1) {
   347 #if cimg_OS==1 && defined(_PTHREAD_H)
   348     if (p.mutex) pthread_mutex_unlock(p.mutex);
   349 #elif cimg_OS==2
   350     ReleaseMutex(p.mutex);
   351 #endif
   352   }
   353 }
   355 static void greycstoration_mutex_destroy(_greycstoration_params &p) {
   356   if (p.nb_threads>1) {
   357 #if cimg_OS==1 && defined(_PTHREAD_H)
   358     if (p.mutex) pthread_mutex_destroy(p.mutex);
   359 #elif cimg_OS==2
   360     CloseHandle(p.mutex);
   361 #endif
   362     p.mutex = 0;
   363   }
   364 }
   366 #if cimg_OS==1
   367 static void* greycstoration_thread(void *arg) {
   368 #elif cimg_OS==2
   369   static DWORD WINAPI greycstoration_thread(void *arg) {
   370 #endif
   371     _greycstoration_params &p = *(_greycstoration_params*)arg;
   372     greycstoration_mutex_lock(p);
   373     const CImg<unsigned char> &mask = *(p.mask);
   374     CImg<T> &source = *(p.source);
   376     if (!p.tile) {
   378       // Non-tiled version
   379       //------------------
   380       if (p.patch_based) source.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
   381       else source.blur_anisotropic(mask,p.amplitude,p.sharpness,p.anisotropy,p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,
   382                                    p.interpolation,p.fast_approx,p.gfact);
   384     } else {
   386       // Tiled version
   387       //---------------
   388       CImg<T> &temporary = *(p.temporary);
   389       const bool threed = (source.depth>1);
   390       const unsigned int b = p.tile_border;
   391       unsigned int ctile = 0;
   392       if (threed) {
   393         for (unsigned int z=0; z<source.depth && !*(p.stop_request); z+=p.tile)
   394           for (unsigned int y=0; y<source.height && !*(p.stop_request); y+=p.tile)
   395             for (unsigned int x=0; x<source.width && !*(p.stop_request); x+=p.tile)
   396               if (!p.nb_threads || ((ctile++)%p.nb_threads)==p.thread) {
   397                 const unsigned int
   398                   x1 = x+p.tile-1,
   399                   y1 = y+p.tile-1,
   400                   z1 = z+p.tile-1,
   401                   xe = x1<source.width?x1:source.width-1,
   402                   ye = y1<source.height?y1:source.height-1,
   403                   ze = z1<source.depth?z1:source.depth-1;
   404                 CImg<T> img = source.get_crop(x-b,y-b,z-b,xe+b,ye+b,ze+b,true);
   405                 CImg<unsigned char> mask_tile = mask.is_empty()?mask:mask.get_crop(x-b,y-b,z-b,xe+b,ye+b,ze+b,true);
   406                 img.greycstoration_params[0] = p;
   407                 greycstoration_mutex_unlock(p);
   408                 if (p.patch_based) img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
   409                 else img.blur_anisotropic(mask_tile,p.amplitude,p.sharpness,p.anisotropy,
   410                                           p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx,p.gfact);
   411                 greycstoration_mutex_lock(p);
   412                 temporary.draw_image(x,y,z,img.crop(b,b,b,img.width-b,img.height-b,img.depth-b));
   413               }
   414       } else {
   415         for (unsigned int y=0; y<source.height && !*(p.stop_request); y+=p.tile)
   416           for (unsigned int x=0; x<source.width && !*(p.stop_request); x+=p.tile)
   417             if (!p.nb_threads || ((ctile++)%p.nb_threads)==p.thread) {
   418               const unsigned int
   419                 x1 = x+p.tile-1,
   420                 y1 = y+p.tile-1,
   421                 xe = x1<source.width?x1:source.width-1,
   422                 ye = y1<source.height?y1:source.height-1;
   423               CImg<T> img = source.get_crop(x-b,y-b,xe+b,ye+b,true);
   424               CImg<unsigned char> mask_tile = mask.is_empty()?mask:mask.get_crop(x-b,y-b,xe+b,ye+b,true);
   425               img.greycstoration_params[0] = p;
   426               greycstoration_mutex_unlock(p);
   427               if (p.patch_based) img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
   428               else img.blur_anisotropic(mask_tile,p.amplitude,p.sharpness,p.anisotropy,
   429                                         p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx,p.gfact);
   430               temporary.draw_image(x,y,img.crop(b,b,img.width-b,img.height-b));
   431               greycstoration_mutex_lock(p);
   432             }
   433       }
   434     }
   435     greycstoration_mutex_unlock(p);
   437     if (!p.thread) {
   438       if (p.nb_threads>1) {
   439         bool stopflag = true;
   440         do {
   441           stopflag = true;
   442           for (unsigned int k=1; k<p.nb_threads; k++) if (source.greycstoration_params[k].is_running) stopflag = false;
   443           if (!stopflag) cimg::wait(50);
   444         } while (!stopflag);
   445       }
   446       if (p.counter) delete p.counter;
   447       if (p.temporary) { source = *(p.temporary); delete p.temporary; }
   448       if (p.stop_request) delete p.stop_request;
   449       p.mask = 0;
   450       p.amplitude = p.sharpness = p.anisotropy = p.alpha = p.sigma = p.gfact = p.dl = p.da = p.gauss_prec = p.sigma_s = p.sigma_p = 0;
   451       p.patch_size = p.interpolation = p.lookup_size = 0;
   452       p.fast_approx = false;
   453       p.source = 0;
   454       p.temporary = 0;
   455       p.counter = 0;
   456       p.tile = p.tile_border = p.thread = p.nb_threads = 0;
   457       p.stop_request = false;
   458       greycstoration_mutex_destroy(p);
   459     }
   460     p.is_running = false;
   462     if (p.nb_threads) {
   463 #if cimg_OS==1 && defined(_PTHREAD_H)
   464       pthread_exit(arg);
   465       return arg;
   466 #elif cimg_OS==2
   467       ExitThread(0);
   468 #endif
   469     }
   470     return 0;
   471   }
   474 #define cimg_plugin_greycstoration_count \
   475   if (!*(greycstoration_params->stop_request)) ++(*greycstoration_params->counter); else return *this;
   476 #define cimg_plugin_greycstoration_lock \
   477   greycstoration_mutex_lock(greycstoration_params[0]);
   478 #define cimg_plugin_greycstoration_unlock \
   479   greycstoration_mutex_unlock(greycstoration_params[0]);
   481 #endif