RafaMar + programmer friend Help button in Batch Render addition
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / greycstoration / greycstoration.h
1 /*
2   #
3   #  File        : greycstoration.h
4   #                ( C++ header file )
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 */
50
51 #ifndef cimg_plugin_greycstoration
52 #define cimg_plugin_greycstoration
53
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 {
61
62   // Tell if the patch-based algorithm is selected
63   bool patch_based;
64
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;
76
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;
82
83   // Non-specific parameters of the algorithms.
84   CImg<T> *source;
85   const CImg<float> *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
103
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 };
110
111 _greycstoration_params greycstoration_params[16];
112
113 //----------------------------------------------------------
114 // Public functions of the GREYCstoration API.
115 // Use the functions below for integrating GREYCstoration
116 // in your own C++ code.
117 //----------------------------------------------------------
118
119 //! Test if GREYCstoration threads are still running.
120 bool greycstoration_is_running() const {
121   return greycstoration_params->is_running;
122 }
123
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 }
132
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 }
151
152 //! Run the non-patch version of the GREYCstoration algorithm on the instance image, using a mask.
153 CImg& greycstoration_run(const CImg<float>& 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) {
159
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,%p).",width(),height(),depth(),data());
163
164   else {
165     if (!mask.is_empty() && !mask.is_sameXY(*this))
166       throw CImgArgumentException("CImg<%s>::greycstoration_run() : Given mask (%u,%u,%u,%p) and instance image "
167                                 "(%u,%u,%u,%p) have different dimensions.",
168                                 pixel_type(),mask.width(),mask.height(),mask.depth(),
169                                 &mask,width(),height(),depth(),data());
170     if (nb_threads>16) cimg::warn("CImg<%s>::greycstoration_run() : Multi-threading mode limited to 16 threads max.");
171     const unsigned int
172       ntile = (tile && (tile<width() || tile<height() || (depth()>1 && tile<depth())))?tile:0,
173 #if cimg_OS==1 && !defined(_PTHREAD_H)
174       nthreads = 0;
175 #else
176     nthreads = ntile?cimg::min(nb_threads,16U):cimg::min(nb_threads,1U);
177 #endif
178
179     CImg<T> *const temporary = ntile?new CImg<T>(*this):0;
180     unsigned long *const counter = new unsigned long;
181     *counter = 0;
182     bool *const stop_request = new bool;
183     *stop_request = false;
184
185     for (unsigned int k=0; k<(nthreads?nthreads:1); k++) {
186       greycstoration_params[k].patch_based = false;
187       greycstoration_params[k].amplitude = amplitude;
188       greycstoration_params[k].sharpness = sharpness;
189       greycstoration_params[k].anisotropy = anisotropy;
190       greycstoration_params[k].alpha = alpha;
191       greycstoration_params[k].sigma = sigma;
192       greycstoration_params[k].gfact = gfact;
193       greycstoration_params[k].dl = dl;
194       greycstoration_params[k].da = da;
195       greycstoration_params[k].gauss_prec = gauss_prec;
196       greycstoration_params[k].interpolation = interpolation;
197       greycstoration_params[k].fast_approx = fast_approx;
198       greycstoration_params[k].source = this;
199       greycstoration_params[k].mask = &mask;
200       greycstoration_params[k].temporary = temporary;
201       greycstoration_params[k].counter = counter;
202       greycstoration_params[k].tile = ntile;
203       greycstoration_params[k].tile_border = tile_border;
204       greycstoration_params[k].thread = k;
205       greycstoration_params[k].nb_threads = nthreads;
206       greycstoration_params[k].is_running = true;
207       greycstoration_params[k].stop_request = stop_request;
208       if (k) greycstoration_params[k].mutex = greycstoration_params[0].mutex;
209       else greycstoration_mutex_create(greycstoration_params[0]);
210     }
211     if (nthreads) {  // Threaded version
212 #if cimg_OS==1
213 #ifdef _PTHREAD_H
214       pthread_attr_t attr;
215       pthread_attr_init(&attr);
216       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
217       for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
218         pthread_t thread;
219         const int err = pthread_create(&thread, &attr, greycstoration_thread, (void*)(greycstoration_params+k));
220         if (err) throw CImgException("CImg<%s>::greycstoration_run() : pthread_create returned error %d",
221                                      pixel_type(), err);
222       }
223 #endif
224 #elif cimg_OS==2
225       for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
226         unsigned long ThreadID = 0;
227         CreateThread(0,0,greycstoration_thread,(void*)(greycstoration_params+k),0,&ThreadID);
228       }
229 #else
230       throw CImgInstanceException("CImg<T>::greycstoration_run() : Threads are not supported, please define cimg_OS first.");
231 #endif
232     } else greycstoration_thread((void*)greycstoration_params); // Non-threaded version
233   }
234   return *this;
235 }
236
237 //! Run the non-patch version of the GREYCstoration algorithm on the instance image.
238 CImg& greycstoration_run(const float amplitude=50, const float sharpness=0.7f, const float anisotropy=0.3f,
239                          const float alpha=0.6f, const float sigma=1.1f, const float gfact=1.0f,
240                          const float dl=0.8f, const float da=30.0f,
241                          const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
242                          const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1) {
243   return greycstoration_run(
244         get_diffusion_tensors(sharpness,anisotropy,alpha,sigma,interpolation!=3),
245         amplitude,sharpness,anisotropy,alpha,sigma,gfact,dl,da,gauss_prec,
246         interpolation,fast_approx,tile,tile_border,nb_threads);
247 }
248
249 //------------------------------------------------------------------------------
250 // GREYCstoration private functions.
251 // Should not be used directly by the API user.
252 //-------------------------------------------------------------------------------
253
254 static void greycstoration_mutex_create(_greycstoration_params &p) {
255   if (p.nb_threads>1) {
256 #if cimg_OS==1 && defined(_PTHREAD_H)
257     p.mutex = new pthread_mutex_t;
258     pthread_mutex_init(p.mutex,0);
259 #elif cimg_OS==2
260     p.mutex = CreateMutex(0,FALSE,0);
261 #endif
262   }
263 }
264
265 static void greycstoration_mutex_lock(_greycstoration_params &p) {
266   if (p.nb_threads>1) {
267 #if cimg_OS==1 && defined(_PTHREAD_H)
268     if (p.mutex) pthread_mutex_lock(p.mutex);
269 #elif cimg_OS==2
270     WaitForSingleObject(p.mutex,INFINITE);
271 #endif
272   }
273 }
274
275 static void greycstoration_mutex_unlock(_greycstoration_params &p) {
276   if (p.nb_threads>1) {
277 #if cimg_OS==1 && defined(_PTHREAD_H)
278     if (p.mutex) pthread_mutex_unlock(p.mutex);
279 #elif cimg_OS==2
280     ReleaseMutex(p.mutex);
281 #endif
282   }
283 }
284
285 static void greycstoration_mutex_destroy(_greycstoration_params &p) {
286   if (p.nb_threads>1) {
287 #if cimg_OS==1 && defined(_PTHREAD_H)
288     if (p.mutex) pthread_mutex_destroy(p.mutex);
289 #elif cimg_OS==2
290     CloseHandle(p.mutex);
291 #endif
292     p.mutex = 0;
293   }
294 }
295
296 #if cimg_OS==1
297 static void* greycstoration_thread(void *arg) {
298 #elif cimg_OS==2
299   static DWORD WINAPI greycstoration_thread(void *arg) {
300 #endif
301     _greycstoration_params &p = *(_greycstoration_params*)arg;
302     greycstoration_mutex_lock(p);
303     const CImg<float> &mask = *(p.mask);
304     CImg<T> &source = *(p.source);
305
306     if (!p.tile) {
307
308       // Non-tiled version
309       //------------------
310       if (p.patch_based) source.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
311       else source.blur_anisotropic(mask,p.amplitude,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx);
312
313     } else {
314
315       // Tiled version
316       //---------------
317       CImg<T> &temporary = *(p.temporary);
318       const bool threed = (source.depth()>1);
319       const unsigned int b = p.tile_border;
320       unsigned int ctile = 0;
321       if (threed) {
322         for (unsigned int z=0; z<source.depth() && !*(p.stop_request); z+=p.tile)
323           for (unsigned int y=0; y<source.height() && !*(p.stop_request); y+=p.tile)
324             for (unsigned int x=0; x<source.width() && !*(p.stop_request); x+=p.tile)
325               if (!p.nb_threads || ((ctile++)%p.nb_threads)==p.thread) {
326                 const unsigned int
327                   x1 = x+p.tile-1,
328                   y1 = y+p.tile-1,
329                   z1 = z+p.tile-1,
330                   xe = x1<source.width()?x1:source.width()-1,
331                   ye = y1<source.height()?y1:source.height()-1,
332                   ze = z1<source.depth()?z1:source.depth()-1;
333                 CImg<T> img = source.get_crop(x-b,y-b,z-b,xe+b,ye+b,ze+b,true);
334                 CImg<float> mask_tile = mask.is_empty()?mask:mask.get_crop(x-b,y-b,z-b,xe+b,ye+b,ze+b,true);
335                 img.greycstoration_params[0] = p;
336                 greycstoration_mutex_unlock(p);
337                 if (p.patch_based) img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
338                 else img.blur_anisotropic(mask_tile,p.amplitude,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx);
339                 greycstoration_mutex_lock(p);
340                 temporary.draw_image(x,y,z,img.crop(b,b,b,img.width()-b,img.height()-b,img.depth()-b));
341               }
342       } else {
343         for (unsigned int y=0; y<source.height() && !*(p.stop_request); y+=p.tile)
344           for (unsigned int x=0; x<source.width() && !*(p.stop_request); x+=p.tile)
345             if (!p.nb_threads || ((ctile++)%p.nb_threads)==p.thread) {
346               const unsigned int
347                 x1 = x+p.tile-1,
348                 y1 = y+p.tile-1,
349                 xe = x1<source.width()?x1:source.width()-1,
350                 ye = y1<source.height()?y1:source.height()-1;
351               CImg<T> img = source.get_crop(x-b,y-b,xe+b,ye+b,true);
352               CImg<float> mask_tile = mask.is_empty()?mask:mask.get_crop(x-b,y-b,xe+b,ye+b,true);
353               img.greycstoration_params[0] = p;
354               greycstoration_mutex_unlock(p);
355               if (p.patch_based) img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
356               else img.blur_anisotropic(mask_tile,p.amplitude,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx);
357               temporary.draw_image(x,y,img.crop(b,b,img.width()-b,img.height()-b));
358               greycstoration_mutex_lock(p);
359             }
360       }
361     }
362     greycstoration_mutex_unlock(p);
363
364     if (!p.thread) {
365       if (p.nb_threads>1) {
366         bool stopflag = true;
367         do {
368           stopflag = true;
369           for (unsigned int k=1; k<p.nb_threads; k++) if (source.greycstoration_params[k].is_running) stopflag = false;
370           if (!stopflag) cimg::wait(50);
371         } while (!stopflag);
372       }
373       if (p.counter) delete p.counter;
374       if (p.temporary) { source = *(p.temporary); delete p.temporary; }
375       if (p.stop_request) { *p.stop_request = false;
376                 delete p.stop_request;}
377       p.mask = 0;
378       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;
379       p.patch_size = p.interpolation = p.lookup_size = 0;
380       p.fast_approx = false;
381       p.source = 0;
382       p.temporary = 0;
383       p.counter = 0;
384       p.tile = p.tile_border = p.thread = p.nb_threads = 0;
385       greycstoration_mutex_destroy(p);
386     }
387     p.is_running = false;
388
389     if (p.nb_threads) {
390 #if cimg_OS==1 && defined(_PTHREAD_H)
391       pthread_exit(arg);
392       return arg;
393 #elif cimg_OS==2
394       ExitThread(0);
395 #endif
396     }
397     return 0;
398   }
399
400
401 #define cimg_plugin_greycstoration_count \
402   if (!*(greycstoration_params->stop_request)) ++(*greycstoration_params->counter); else return *this;
403 #define cimg_plugin_greycstoration_lock \
404   greycstoration_mutex_lock(greycstoration_params[0]);
405 #define cimg_plugin_greycstoration_unlock \
406   greycstoration_mutex_unlock(greycstoration_params[0]);
407
408 #endif