Wed, 05 Aug 2009 17:10:56 +0100
add 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