~ubuntu-branches/ubuntu/trusty/digikam/trusty

« back to all changes in this revision

Viewing changes to core/libs/3rdparty/cimg/greycstoration.h

  • Committer: Package Import Robot
  • Author(s): Rohan Garg
  • Date: 2012-11-26 18:24:20 UTC
  • mfrom: (1.9.1) (3.1.23 experimental)
  • Revision ID: package-import@ubuntu.com-20121126182420-qoy6z0nx4ai0wzcl
Tags: 4:3.0.0~beta3-0ubuntu1
* New upstream release
  - Add build-deps :  libhupnp-dev, libqtgstreamer-dev, libmagickcore-dev
* Merge from debian, remaining changes:
  - Make sure libqt4-opengl-dev, libgl1-mesa-dev and libglu1-mesa-dev only
    install on i386,amd64 and powerpc
  - Depend on libtiff-dev instead of libtiff4-dev
  - Drop digikam breaks/replaces kipi-plugins-common since we're past the
    LTS release now
  - digikam to recommend mplayerthumbs | ffmpegthumbs. We currently only
    have latter in the archives, even though former is also supposed to
    be part of kdemultimedia. (LP: #890059)
  - kipi-plugins to recommend www-browser rather than konqueror directly
    since 2.8 no direct usage of konqueror is present in the flickr
    plugin anymore (LP: #1011211)
  - Keep kubuntu_mysqld_executable_name.diff
  - Don't install libkipi translations
  - Keep deps on libcv-dev, libcvaux-dev
  - Keep split packaging of libraries
  - Replace icons from KDE 3 time in debian/xpm.d/*.xpm with the new
    versions (LP: #658047)
* Update debian/not-installed

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
#ifndef cimg_plugin_greycstoration
52
52
#define cimg_plugin_greycstoration
53
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 {
 
54
// NOTE: You need to include
 
55
// #include <QMutex>
 
56
// #include <QMutexLocker>
 
57
//
 
58
// #include "dynamicthread.h"
 
59
 
 
60
class GreycstorationParameters {
 
61
public:
61
62
 
62
63
  // Tell if the patch-based algorithm is selected
63
64
  bool patch_based;
81
82
  unsigned int lookup_size;
82
83
 
83
84
  // 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
85
  unsigned int tile;
89
86
  unsigned int tile_border;
90
 
  unsigned int thread;
91
 
  unsigned int nb_threads;
92
87
  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
88
 
104
89
  // 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<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) {
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,%u,%p).",width,height,depth,dim,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,%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
177
 
 
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;
183
 
 
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
 
}
235
 
 
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
 
}
246
 
 
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) {
251
 
 
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);
256
 
 
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
266
 
 
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;
272
 
 
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
 
}
318
 
 
319
 
//------------------------------------------------------------------------------
320
 
// GREYCstoration private functions.
321
 
// Should not be used directly by the API user.
322
 
//-------------------------------------------------------------------------------
323
 
 
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
 
}
334
 
 
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
 
}
344
 
 
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
 
}
354
 
 
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
 
}
365
 
 
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);
375
 
 
376
 
    if (!p.tile) {
377
 
 
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);
383
 
 
384
 
    } else {
385
 
 
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);
436
 
 
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;
461
 
 
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
 
  }
472
 
 
 
90
  GreycstorationParameters()
 
91
    : patch_based(false),
 
92
      amplitude(0),
 
93
      sharpness(0),
 
94
      anisotropy(0),
 
95
      alpha(0),
 
96
      sigma(0),
 
97
      gfact(1),
 
98
      dl(0),
 
99
      da(0),
 
100
      gauss_prec(0),
 
101
      interpolation(0),
 
102
      patch_size(0),
 
103
      sigma_s(0),
 
104
      sigma_p(0),
 
105
      lookup_size(0),
 
106
      tile(0),
 
107
      tile_border(0),
 
108
      fast_approx(false) {}
 
109
};
 
110
 
 
111
class GreycstorationThreadManager;
 
112
// class just to have a constructor to initialize the variable
 
113
class GreycstorationThreadManagerContainer
 
114
{
 
115
public:
 
116
    GreycstorationThreadManagerContainer() : threadManager(0) {}
 
117
    GreycstorationThreadManager* threadManager;
 
118
};
 
119
GreycstorationThreadManagerContainer threadManagerContainer;
 
120
 
 
121
void setThreadManager(GreycstorationThreadManager* threadManager)
 
122
{
 
123
    threadManagerContainer.threadManager = threadManager;
 
124
}
 
125
 
 
126
void resetThreadManager()
 
127
{
 
128
    setThreadManager(0);
 
129
}
 
130
 
 
131
class GreycstorationWorkingThread : public Digikam::DynamicThread
 
132
{
 
133
public:
 
134
    GreycstorationWorkingThread(GreycstorationThreadManager* manager, int threadNumber)
 
135
        : manager(manager), threadNumber(threadNumber)
 
136
    {
 
137
    }
 
138
 
 
139
    virtual void run()
 
140
    {
 
141
        manager->workerMethod(threadNumber);
 
142
    }
 
143
 
 
144
    GreycstorationThreadManager* const manager;
 
145
    const int threadNumber;
 
146
};
 
147
 
 
148
//template <typename T>
 
149
class GreycstorationThreadManager
 
150
{
 
151
public:
 
152
    GreycstorationThreadManager()
 
153
        : counter(0), stopRequest(false), activeThreads(0),
 
154
          source(0), temporary(0), empty_mask(new CImg<unsigned char>())
 
155
    {
 
156
    }
 
157
 
 
158
    ~GreycstorationThreadManager()
 
159
    {
 
160
        stop();
 
161
        wait();
 
162
        finish();
 
163
        qDeleteAll(threads);
 
164
        delete temporary;
 
165
        delete empty_mask;
 
166
    }
 
167
 
 
168
 
 
169
    //! Run the non-patch version of the GREYCstoration algorithm on the instance image, using a mask.
 
170
    void start(CImg& s, const CImg<unsigned char>* m,
 
171
               const float amplitude=60, const float sharpness=0.7f,
 
172
               const float anisotropy=0.3f, const float alpha=0.6f,
 
173
               const float sigma=1.1f, const float gfact=1.0f,
 
174
               const float dl=0.8f, const float da=30.0f,
 
175
               const float gauss_prec=2.0f, const unsigned int interpolation=0,
 
176
               const bool fast_approx=true, const unsigned int tile=0,
 
177
               const unsigned int tile_border=0,
 
178
               const unsigned int nb_threads=1)
 
179
    {
 
180
 
 
181
        GreycstorationParameters params;
 
182
        params.patch_based = false;
 
183
 
 
184
        params.amplitude = amplitude;
 
185
        params.sharpness = sharpness;
 
186
        params.anisotropy = anisotropy;
 
187
        params.alpha = alpha;
 
188
        params.sigma = sigma;
 
189
        params.gfact = gfact;
 
190
        params.dl = dl;
 
191
        params.da = da;
 
192
        params.gauss_prec = gauss_prec;
 
193
        params.interpolation = interpolation;
 
194
        params.fast_approx = fast_approx;
 
195
        params.tile_border = tile_border;
 
196
 
 
197
        mask = m;
 
198
        start(&s, params, tile, nb_threads);
 
199
    }
 
200
 
 
201
    //! Run the non-patch version of the GREYCstoration algorithm on the instance image.
 
202
    void start(CImg& s, const float amplitude=50, const float sharpness=0.7f, const float anisotropy=0.3f,
 
203
               const float alpha=0.6f, const float sigma=1.1f, const float gfact=1.0f,
 
204
               const float dl=0.8f, const float da=30.0f,
 
205
               const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
 
206
               const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1)
 
207
    {
 
208
        return start(s, empty_mask, amplitude,sharpness,anisotropy,alpha,sigma,gfact,dl,da,gauss_prec,
 
209
                    interpolation,fast_approx,tile,tile_border,nb_threads);
 
210
    }
 
211
 
 
212
    //! Run the patch-based version of the GREYCstoration algorithm on the instance image.
 
213
    void start(CImg& s, const unsigned int patch_size=5,
 
214
               const float sigma_p=10,
 
215
               const float sigma_s=100,
 
216
               const unsigned int lookup_size=20,
 
217
               const bool fast_approx=true,
 
218
               const unsigned int tile=0,
 
219
               const unsigned int tile_border=0,
 
220
               const unsigned int nb_threads=1)
 
221
    {
 
222
        GreycstorationParameters params;
 
223
 
 
224
        params.patch_based = true;
 
225
        params.patch_size = patch_size;
 
226
        params.sigma_s = sigma_s;
 
227
        params.sigma_p = sigma_p;
 
228
        params.lookup_size = lookup_size;
 
229
        params.mask = empty_mask;
 
230
        params.tile_border = tile_border;
 
231
        params.fast_approx = fast_approx;
 
232
 
 
233
        start(&s, params, tile, nb_threads);
 
234
    }
 
235
 
 
236
    bool isRunning() const
 
237
    {
 
238
        foreach(GreycstorationWorkingThread* thread, threads)
 
239
        {
 
240
            if (thread->isRunning())
 
241
            {
 
242
                return true;
 
243
            }
 
244
        }
 
245
        return false;
 
246
    }
 
247
 
 
248
    void wait()
 
249
    {
 
250
        foreach(GreycstorationWorkingThread* thread, threads)
 
251
        {
 
252
            thread->wait();
 
253
        }
 
254
    }
 
255
 
 
256
    void finish()
 
257
    {
 
258
        if (temporary)
 
259
        {
 
260
            (*source) = (*temporary);
 
261
        }
 
262
        if (source)
 
263
        {
 
264
            source->resetThreadManager();
 
265
        }
 
266
    }
 
267
 
 
268
    void stop()
 
269
    {
 
270
        foreach(GreycstorationWorkingThread* thread, threads)
 
271
        {
 
272
            thread->stop();
 
273
        }
 
274
        stopRequest = true;
 
275
    }
 
276
 
 
277
    float progress() const
 
278
    {
 
279
        const float
 
280
        da = p.da,
 
281
        factor = p.patch_based ? 1 : (1+360/da);
 
282
        float maxcounter = 0;
 
283
        if (p.tile==0)
 
284
        {
 
285
            maxcounter = source->width*source->height*source->depth*factor;
 
286
        }
 
287
        else
 
288
        {
 
289
            const unsigned int
 
290
            t = p.tile,
 
291
            b = p.tile_border,
 
292
            n = (1+(source->width-1)/t)*(1+(source->height-1)/t)*(1+(source->depth-1)/t);
 
293
            maxcounter = (source->width*source->height*source->depth + n*4*b*(b + t))*factor;
 
294
        }
 
295
        return cimg::min(counter*99.9f/maxcounter,99.9f);
 
296
    }
 
297
 
 
298
    // Waits at most the specified number of milliseconds, then returns current progress
 
299
    float waitABit(unsigned int msecs)
 
300
    {
 
301
        QMutexLocker lock(&mutex);
 
302
        if (activeThreads)
 
303
        {
 
304
            condVar.wait(&mutex, msecs);
 
305
        }
 
306
        return progress();
 
307
    }
 
308
 
 
309
protected:
 
310
 
 
311
    friend class CImg<T>;
 
312
 
 
313
    QMutex         mutex;
 
314
    QWaitCondition condVar;
 
315
    volatile int   counter;
 
316
    volatile bool  stopRequest;
 
317
    volatile int   activeThreads;
 
318
 
 
319
    GreycstorationParameters p;
 
320
 
 
321
    CImg<T>*                   source;
 
322
    const CImg<unsigned char> *mask;
 
323
    CImg<T>                   *temporary;
 
324
    
 
325
    CImg<unsigned char> *empty_mask;
 
326
 
 
327
    QList<GreycstorationWorkingThread*> threads;
 
328
 
 
329
    void start(CImg* s, const GreycstorationParameters& params, unsigned int tile, unsigned int numberOfThreads)
 
330
    {
 
331
        /*if (!mask.is_empty() && !mask.is_sameXY(*this))
 
332
        {
 
333
            throw CImgArgumentException("CImg<%s>::greycstoration_run() : Given mask (%u,%u,%u,%u,%p) and instance image "
 
334
                                        "(%u,%u,%u,%u,%p) have different dimensions.",
 
335
                                        pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data,width,height,depth,dim,data);
 
336
        }*/
 
337
 
 
338
        if (numberOfThreads>16)
 
339
        {
 
340
            cimg::warn("CImg<%s>::greycstoration_run() : Multi-threading mode limited to 16 threads max.");
 
341
        }
 
342
 
 
343
        source = s;
 
344
        s->setThreadManager(this);
 
345
        p = params;
 
346
 
 
347
        p.tile = (tile && (tile<source->width || tile<source->height ||
 
348
                        (source->depth>1 && tile<source->depth)))?tile:0,
 
349
        numberOfThreads = p.tile ? cimg::min(numberOfThreads,16U) : cimg::min(numberOfThreads,1U);
 
350
 
 
351
        counter = 0;
 
352
        stopRequest = false;
 
353
        activeThreads = 0;
 
354
        delete temporary;
 
355
        temporary = p.tile ? new CImg<T>(*source) : 0;
 
356
 
 
357
        if (numberOfThreads)
 
358
        {
 
359
            for (unsigned int k=0; k<numberOfThreads; k++)
 
360
            {
 
361
                GreycstorationWorkingThread* thread = new GreycstorationWorkingThread(this, k);
 
362
                ++activeThreads;
 
363
                thread->start();
 
364
                threads << thread;
 
365
            }
 
366
        }
 
367
        else
 
368
        {
 
369
            // direct execution
 
370
            ++activeThreads;
 
371
            workerMethod(0);
 
372
        }
 
373
    }
 
374
 
 
375
    friend class GreycstorationWorkingThread;
 
376
    void workerMethod(unsigned int threadIndex)
 
377
    {
 
378
        QMutexLocker lock(&mutex);
 
379
 
 
380
        if (!p.tile)
 
381
        {
 
382
            // Non-tiled version
 
383
            //------------------
 
384
            if (p.patch_based)
 
385
            {
 
386
                source->blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
 
387
            }
 
388
            else
 
389
            {
 
390
                source->blur_anisotropic(*mask,p.amplitude,p.sharpness,p.anisotropy,p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,
 
391
                                        p.interpolation,p.fast_approx,p.gfact);
 
392
            }
 
393
        }
 
394
        else
 
395
        {
 
396
            // Tiled version
 
397
            //---------------
 
398
            const bool threed = (source->depth>1);
 
399
            const unsigned int b = p.tile_border;
 
400
            unsigned int ctile = 0;
 
401
 
 
402
            if (threed)
 
403
            {
 
404
                for (unsigned int z=0; z<source->depth && !stopRequest; z+=p.tile)
 
405
                {
 
406
                    for (unsigned int y=0; y<source->height && !stopRequest; y+=p.tile)
 
407
                    {
 
408
                        for (unsigned int x=0; x<source->width && !stopRequest; x+=p.tile)
 
409
                        {
 
410
                            if (threads.isEmpty() || ((ctile++)%threads.size())==(unsigned int)threadIndex)
 
411
                            {
 
412
                                const unsigned int
 
413
                                x1 = x+p.tile-1,
 
414
                                y1 = y+p.tile-1,
 
415
                                z1 = z+p.tile-1,
 
416
                                xe = x1<source->width?x1:source->width-1,
 
417
                                ye = y1<source->height?y1:source->height-1,
 
418
                                ze = z1<source->depth?z1:source->depth-1;
 
419
 
 
420
                                CImg<T> img = source->get_crop(x-b,y-b,z-b,xe+b,ye+b,ze+b,true);
 
421
                                CImg<unsigned char> mask_tile = mask->is_empty() ? *mask :
 
422
                                                                mask->get_crop(x-b,y-b,z-b,xe+b,ye+b,ze+b,true);
 
423
                                //??img.greycstoration_params[0] = p;
 
424
 
 
425
                                lock.unlock();
 
426
                                if (p.patch_based)
 
427
                                {
 
428
                                    img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
 
429
                                }
 
430
                                else
 
431
                                {
 
432
                                    img.blur_anisotropic(mask_tile,p.amplitude,p.sharpness,p.anisotropy,
 
433
                                                         p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx,p.gfact);
 
434
                                }
 
435
                                lock.relock();
 
436
 
 
437
                                temporary->draw_image(x,y,z,img.crop(b,b,b,img.width-b,img.height-b,img.depth-b));
 
438
                            }
 
439
                        }
 
440
                    }
 
441
                }
 
442
            }
 
443
            else
 
444
            {
 
445
                for (unsigned int y=0; y<source->height && !stopRequest; y+=p.tile)
 
446
                {
 
447
                    for (unsigned int x=0; x<source->width && !stopRequest; x+=p.tile)
 
448
                    {
 
449
                        if (threads.isEmpty() || ((ctile++)%threads.size())==(unsigned int)threadIndex)
 
450
                        {
 
451
                            const unsigned int
 
452
                            x1 = x+p.tile-1,
 
453
                            y1 = y+p.tile-1,
 
454
                            xe = x1<source->width?x1:source->width-1,
 
455
                            ye = y1<source->height?y1:source->height-1;
 
456
                            CImg<T> img = source->get_crop(x-b,y-b,xe+b,ye+b,true);
 
457
                            CImg<unsigned char> mask_tile = mask->is_empty() ? *mask : mask->get_crop(x-b,y-b,xe+b,ye+b,true);
 
458
                            //img.greycstoration_params[0] = p;
 
459
 
 
460
                            lock.unlock();
 
461
                            if (p.patch_based)
 
462
                            {
 
463
                                img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
 
464
                            }
 
465
                            else
 
466
                            {
 
467
                                img.blur_anisotropic(mask_tile,p.amplitude,p.sharpness,p.anisotropy,
 
468
                                                     p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx,p.gfact);
 
469
                            }
 
470
                            lock.relock();
 
471
 
 
472
                            temporary->draw_image(x,y,img.crop(b,b,img.width-b,img.height-b));
 
473
                        }
 
474
                    }
 
475
                }
 
476
            }
 
477
        }
 
478
        --activeThreads;
 
479
        condVar.wakeAll();
 
480
    }
 
481
 
 
482
};
473
483
 
474
484
#define cimg_plugin_greycstoration_count \
475
 
  if (!*(greycstoration_params->stop_request)) ++(*greycstoration_params->counter); else return *this;
 
485
  if (threadManagerContainer.threadManager)\
 
486
  { if (threadManagerContainer.threadManager->stopRequest) \
 
487
        return *this; \
 
488
    ++threadManagerContainer.threadManager->counter; }
 
489
 
476
490
#define cimg_plugin_greycstoration_lock \
477
 
  greycstoration_mutex_lock(greycstoration_params[0]);
 
491
  if (threadManagerContainer.threadManager) threadManagerContainer.threadManager->mutex.lock();
478
492
#define cimg_plugin_greycstoration_unlock \
479
 
  greycstoration_mutex_unlock(greycstoration_params[0]);
 
493
  if (threadManagerContainer.threadManager) threadManagerContainer.threadManager->mutex.unlock();
480
494
 
481
495
#endif