00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 #ifndef cimg_plugin_greycstoration
00052 #define cimg_plugin_greycstoration
00053
00054
00055
00056
00057
00058
00059
00060 struct _greycstoration_params {
00061
00062
00063 bool patch_based;
00064
00065
00066 float amplitude;
00067 float sharpness;
00068 float anisotropy;
00069 float alpha;
00070 float sigma;
00071 float gfact;
00072 float dl;
00073 float da;
00074 float gauss_prec;
00075 unsigned int interpolation;
00076
00077
00078 unsigned int patch_size;
00079 float sigma_s;
00080 float sigma_p;
00081 unsigned int lookup_size;
00082
00083
00084 CImg<T> *source;
00085 const CImg<unsigned char> *mask;
00086 CImg<T> *temporary;
00087 unsigned long *counter;
00088 unsigned int tile;
00089 unsigned int tile_border;
00090 unsigned int thread;
00091 unsigned int nb_threads;
00092 bool fast_approx;
00093 bool is_running;
00094 bool *stop_request;
00095 #if cimg_OS==1 && defined(_PTHREAD_H)
00096 pthread_mutex_t
00097 *mutex;
00098 #elif cimg_OS==2
00099 HANDLE mutex;
00100 #else
00101 void *mutex;
00102 #endif
00103
00104
00105 _greycstoration_params():patch_based(false),amplitude(0),sharpness(0),anisotropy(0),alpha(0),sigma(0),gfact(1),
00106 dl(0),da(0),gauss_prec(0),interpolation(0),patch_size(0),
00107 sigma_s(0),sigma_p(0),lookup_size(0),source(0),mask(0),temporary(0),counter(0),tile(0),
00108 tile_border(0),thread(0),nb_threads(0),fast_approx(false),is_running(false), stop_request(0), mutex(0) {}
00109 };
00110
00111 _greycstoration_params greycstoration_params[16];
00112
00113
00114
00115
00116
00117
00118
00120 bool greycstoration_is_running() const {
00121 return greycstoration_params->is_running;
00122 }
00123
00125 CImg& greycstoration_stop() {
00126 if (greycstoration_is_running()) {
00127 *(greycstoration_params->stop_request) = true;
00128 while (greycstoration_params->is_running) cimg::wait(50);
00129 }
00130 return *this;
00131 }
00132
00134 float greycstoration_progress() const {
00135 if (!greycstoration_is_running()) return 0.0f;
00136 const unsigned long counter = greycstoration_params->counter?*(greycstoration_params->counter):0;
00137 const float
00138 da = greycstoration_params->da,
00139 factor = greycstoration_params->patch_based?1:(1+360/da);
00140 float maxcounter = 0;
00141 if (greycstoration_params->tile==0) maxcounter = width*height*depth*factor;
00142 else {
00143 const unsigned int
00144 t = greycstoration_params->tile,
00145 b = greycstoration_params->tile_border,
00146 n = (1+(width-1)/t)*(1+(height-1)/t)*(1+(depth-1)/t);
00147 maxcounter = (width*height*depth + n*4*b*(b + t))*factor;
00148 }
00149 return cimg::min(counter*99.9f/maxcounter,99.9f);
00150 }
00151
00153 CImg& greycstoration_run(const CImg<unsigned char>& mask,
00154 const float amplitude=60, const float sharpness=0.7f, const float anisotropy=0.3f,
00155 const float alpha=0.6f, const float sigma=1.1f, const float gfact=1.0f,
00156 const float dl=0.8f, const float da=30.0f,
00157 const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
00158 const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1) {
00159
00160 if (greycstoration_is_running())
00161 throw CImgInstanceException("CImg<T>::greycstoration_run() : A GREYCstoration thread is already running on"
00162 " the instance image (%u,%u,%u,%u,%p).",width,height,depth,dim,data);
00163
00164 else {
00165 if (!mask.is_empty() && !mask.is_sameXY(*this))
00166 throw CImgArgumentException("CImg<%s>::greycstoration_run() : Given mask (%u,%u,%u,%u,%p) and instance image "
00167 "(%u,%u,%u,%u,%p) have different dimensions.",
00168 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data,width,height,depth,dim,data);
00169 if (nb_threads>16) cimg::warn("CImg<%s>::greycstoration_run() : Multi-threading mode limited to 16 threads max.");
00170 const unsigned int
00171 ntile = (tile && (tile<width || tile<height || (depth>1 && tile<depth)))?tile:0,
00172 #if cimg_OS==1 && !defined(_PTHREAD_H)
00173 nthreads = 0;
00174 #else
00175 nthreads = ntile?cimg::min(nb_threads,16U):cimg::min(nb_threads,1U);
00176 #endif
00177
00178 CImg<T> *const temporary = ntile?new CImg<T>(*this):0;
00179 unsigned long *const counter = new unsigned long;
00180 *counter = 0;
00181 bool *const stop_request = new bool;
00182 *stop_request = false;
00183
00184 for (unsigned int k=0; k<(nthreads?nthreads:1); k++) {
00185 greycstoration_params[k].patch_based = false;
00186 greycstoration_params[k].amplitude = amplitude;
00187 greycstoration_params[k].sharpness = sharpness;
00188 greycstoration_params[k].anisotropy = anisotropy;
00189 greycstoration_params[k].alpha = alpha;
00190 greycstoration_params[k].sigma = sigma;
00191 greycstoration_params[k].gfact = gfact;
00192 greycstoration_params[k].dl = dl;
00193 greycstoration_params[k].da = da;
00194 greycstoration_params[k].gauss_prec = gauss_prec;
00195 greycstoration_params[k].interpolation = interpolation;
00196 greycstoration_params[k].fast_approx = fast_approx;
00197 greycstoration_params[k].source = this;
00198 greycstoration_params[k].mask = &mask;
00199 greycstoration_params[k].temporary = temporary;
00200 greycstoration_params[k].counter = counter;
00201 greycstoration_params[k].tile = ntile;
00202 greycstoration_params[k].tile_border = tile_border;
00203 greycstoration_params[k].thread = k;
00204 greycstoration_params[k].nb_threads = nthreads;
00205 greycstoration_params[k].is_running = true;
00206 greycstoration_params[k].stop_request = stop_request;
00207 if (k) greycstoration_params[k].mutex = greycstoration_params[0].mutex;
00208 else greycstoration_mutex_create(greycstoration_params[0]);
00209 }
00210 if (nthreads) {
00211 #if cimg_OS==1
00212 #ifdef _PTHREAD_H
00213 pthread_attr_t attr;
00214 pthread_attr_init(&attr);
00215 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00216 for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
00217 pthread_t thread;
00218 const int err = pthread_create(&thread, &attr, greycstoration_thread, (void*)(greycstoration_params+k));
00219 if (err) throw CImgException("CImg<%s>::greycstoration_run() : pthread_create returned error %d",
00220 pixel_type(), err);
00221 }
00222 #endif
00223 #elif cimg_OS==2
00224 for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
00225 unsigned long ThreadID = 0;
00226 CreateThread(0,0,greycstoration_thread,(void*)(greycstoration_params+k),0,&ThreadID);
00227 }
00228 #else
00229 throw CImgInstanceException("CImg<T>::greycstoration_run() : Threads are not supported, please define cimg_OS first.");
00230 #endif
00231 } else greycstoration_thread((void*)greycstoration_params);
00232 }
00233 return *this;
00234 }
00235
00237 CImg& greycstoration_run(const float amplitude=50, const float sharpness=0.7f, const float anisotropy=0.3f,
00238 const float alpha=0.6f, const float sigma=1.1f, const float gfact=1.0f,
00239 const float dl=0.8f, const float da=30.0f,
00240 const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
00241 const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1) {
00242 static const CImg<unsigned char> empty_mask;
00243 return greycstoration_run(empty_mask,amplitude,sharpness,anisotropy,alpha,sigma,gfact,dl,da,gauss_prec,
00244 interpolation,fast_approx,tile,tile_border,nb_threads);
00245 }
00246
00248 CImg& greycstoration_patch_run(const unsigned int patch_size=5, const float sigma_p=10, const float sigma_s=100,
00249 const unsigned int lookup_size=20, const bool fast_approx=true,
00250 const unsigned int tile=0, const unsigned int tile_border=0, const unsigned int nb_threads=1) {
00251
00252 static const CImg<unsigned char> empty_mask;
00253 if (greycstoration_is_running())
00254 throw CImgInstanceException("CImg<T>::greycstoration_run() : A GREYCstoration thread is already running on"
00255 " the instance image (%u,%u,%u,%u,%p).",width,height,depth,dim,data);
00256
00257 else {
00258 if (nb_threads>16) cimg::warn("CImg<%s>::greycstoration_run() : Multi-threading mode limited to 16 threads max.");
00259 const unsigned int
00260 ntile = (tile && (tile<width || tile<height || (depth>1 && tile<depth)))?tile:0,
00261 #if cimg_OS==1 && !defined(_PTHREAD_H)
00262 nthreads = 0;
00263 #else
00264 nthreads = ntile?cimg::min(nb_threads,16U):cimg::min(nb_threads,1U);
00265 #endif
00266
00267 CImg<T> *const temporary = ntile?new CImg<T>(*this):0;
00268 unsigned long *const counter = new unsigned long;
00269 *counter = 0;
00270 bool *const stop_request = new bool;
00271 *stop_request = false;
00272
00273 for (unsigned int k=0; k<(nthreads?nthreads:1); k++) {
00274 greycstoration_params[k].patch_based = true;
00275 greycstoration_params[k].patch_size = patch_size;
00276 greycstoration_params[k].sigma_s = sigma_s;
00277 greycstoration_params[k].sigma_p = sigma_p;
00278 greycstoration_params[k].lookup_size = lookup_size;
00279 greycstoration_params[k].source = this;
00280 greycstoration_params[k].mask = &empty_mask;
00281 greycstoration_params[k].temporary = temporary;
00282 greycstoration_params[k].counter = counter;
00283 greycstoration_params[k].tile = ntile;
00284 greycstoration_params[k].tile_border = tile_border;
00285 greycstoration_params[k].thread = k;
00286 greycstoration_params[k].nb_threads = nthreads;
00287 greycstoration_params[k].fast_approx = fast_approx;
00288 greycstoration_params[k].is_running = true;
00289 greycstoration_params[k].stop_request = stop_request;
00290 if (k) greycstoration_params[k].mutex = greycstoration_params[0].mutex;
00291 else greycstoration_mutex_create(greycstoration_params[0]);
00292 }
00293 if (nthreads) {
00294 #if cimg_OS==1
00295 #ifdef _PTHREAD_H
00296 pthread_attr_t attr;
00297 pthread_attr_init(&attr);
00298 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00299 for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
00300 pthread_t thread;
00301 const int err = pthread_create(&thread, &attr, greycstoration_thread, (void*)(greycstoration_params+k));
00302 if (err) throw CImgException("CImg<%s>::greycstoration_run() : pthread_create returned error %d",
00303 pixel_type(), err);
00304 }
00305 #endif
00306 #elif cimg_OS==2
00307 for (unsigned int k=0; k<greycstoration_params->nb_threads; k++) {
00308 unsigned long ThreadID = 0;
00309 CreateThread(0,0,greycstoration_thread,(void*)(greycstoration_params+k),0,&ThreadID);
00310 }
00311 #else
00312 throw CImgInstanceException("CImg<T>::greycstoration_run() : Threads support have not been enabled in this version of GREYCstoration.");
00313 #endif
00314 } else greycstoration_thread((void*)greycstoration_params);
00315 }
00316 return *this;
00317 }
00318
00319
00320
00321
00322
00323
00324 static void greycstoration_mutex_create(_greycstoration_params &p) {
00325 if (p.nb_threads>1) {
00326 #if cimg_OS==1 && defined(_PTHREAD_H)
00327 p.mutex = new pthread_mutex_t;
00328 pthread_mutex_init(p.mutex,0);
00329 #elif cimg_OS==2
00330 p.mutex = CreateMutex(0,FALSE,0);
00331 #endif
00332 }
00333 }
00334
00335 static void greycstoration_mutex_lock(_greycstoration_params &p) {
00336 if (p.nb_threads>1) {
00337 #if cimg_OS==1 && defined(_PTHREAD_H)
00338 if (p.mutex) pthread_mutex_lock(p.mutex);
00339 #elif cimg_OS==2
00340 WaitForSingleObject(p.mutex,INFINITE);
00341 #endif
00342 }
00343 }
00344
00345 static void greycstoration_mutex_unlock(_greycstoration_params &p) {
00346 if (p.nb_threads>1) {
00347 #if cimg_OS==1 && defined(_PTHREAD_H)
00348 if (p.mutex) pthread_mutex_unlock(p.mutex);
00349 #elif cimg_OS==2
00350 ReleaseMutex(p.mutex);
00351 #endif
00352 }
00353 }
00354
00355 static void greycstoration_mutex_destroy(_greycstoration_params &p) {
00356 if (p.nb_threads>1) {
00357 #if cimg_OS==1 && defined(_PTHREAD_H)
00358 if (p.mutex) pthread_mutex_destroy(p.mutex);
00359 #elif cimg_OS==2
00360 CloseHandle(p.mutex);
00361 #endif
00362 p.mutex = 0;
00363 }
00364 }
00365
00366 #if cimg_OS==1
00367 static void* greycstoration_thread(void *arg) {
00368 #elif cimg_OS==2
00369 static DWORD WINAPI greycstoration_thread(void *arg) {
00370 #endif
00371 _greycstoration_params &p = *(_greycstoration_params*)arg;
00372 greycstoration_mutex_lock(p);
00373 const CImg<unsigned char> &mask = *(p.mask);
00374 CImg<T> &source = *(p.source);
00375
00376 if (!p.tile) {
00377
00378
00379
00380 if (p.patch_based) source.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
00381 else source.blur_anisotropic(mask,p.amplitude,p.sharpness,p.anisotropy,p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,
00382 p.interpolation,p.fast_approx,p.gfact);
00383
00384 } else {
00385
00386
00387
00388 CImg<T> &temporary = *(p.temporary);
00389 const bool threed = (source.depth>1);
00390 const unsigned int b = p.tile_border;
00391 unsigned int ctile = 0;
00392 if (threed) {
00393 for (unsigned int z=0; z<source.depth && !*(p.stop_request); z+=p.tile)
00394 for (unsigned int y=0; y<source.height && !*(p.stop_request); y+=p.tile)
00395 for (unsigned int x=0; x<source.width && !*(p.stop_request); x+=p.tile)
00396 if (!p.nb_threads || ((ctile++)%p.nb_threads)==p.thread) {
00397 const unsigned int
00398 x1 = x+p.tile-1,
00399 y1 = y+p.tile-1,
00400 z1 = z+p.tile-1,
00401 xe = x1<source.width?x1:source.width-1,
00402 ye = y1<source.height?y1:source.height-1,
00403 ze = z1<source.depth?z1:source.depth-1;
00404 CImg<T> img = source.get_crop(x-b,y-b,z-b,xe+b,ye+b,ze+b,true);
00405 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);
00406 img.greycstoration_params[0] = p;
00407 greycstoration_mutex_unlock(p);
00408 if (p.patch_based) img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
00409 else img.blur_anisotropic(mask_tile,p.amplitude,p.sharpness,p.anisotropy,
00410 p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx,p.gfact);
00411 greycstoration_mutex_lock(p);
00412 temporary.draw_image(img.crop(b,b,b,img.width-b,img.height-b,img.depth-b),x,y,z);
00413 }
00414 } else {
00415 for (unsigned int y=0; y<source.height && !*(p.stop_request); y+=p.tile)
00416 for (unsigned int x=0; x<source.width && !*(p.stop_request); x+=p.tile)
00417 if (!p.nb_threads || ((ctile++)%p.nb_threads)==p.thread) {
00418 const unsigned int
00419 x1 = x+p.tile-1,
00420 y1 = y+p.tile-1,
00421 xe = x1<source.width?x1:source.width-1,
00422 ye = y1<source.height?y1:source.height-1;
00423 CImg<T> img = source.get_crop(x-b,y-b,xe+b,ye+b,true);
00424 CImg<unsigned char> mask_tile = mask.is_empty()?mask:mask.get_crop(x-b,y-b,xe+b,ye+b,true);
00425 img.greycstoration_params[0] = p;
00426 greycstoration_mutex_unlock(p);
00427 if (p.patch_based) img.blur_patch(p.patch_size,p.sigma_p,p.sigma_s,p.lookup_size,p.fast_approx);
00428 else img.blur_anisotropic(mask_tile,p.amplitude,p.sharpness,p.anisotropy,
00429 p.alpha,p.sigma,p.dl,p.da,p.gauss_prec,p.interpolation,p.fast_approx,p.gfact);
00430 temporary.draw_image(img.crop(b,b,img.width-b,img.height-b),x,y);
00431 greycstoration_mutex_lock(p);
00432 }
00433 }
00434 }
00435 greycstoration_mutex_unlock(p);
00436
00437 if (!p.thread) {
00438 if (p.nb_threads>1) {
00439 bool stopflag = true;
00440 do {
00441 stopflag = true;
00442 for (unsigned int k=1; k<p.nb_threads; k++) if (source.greycstoration_params[k].is_running) stopflag = false;
00443 if (!stopflag) cimg::wait(50);
00444 } while (!stopflag);
00445 }
00446 if (p.counter) delete p.counter;
00447 if (p.temporary) { source = *(p.temporary); delete p.temporary; }
00448 if (p.stop_request) delete p.stop_request;
00449 p.mask = 0;
00450 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;
00451 p.patch_size = p.interpolation = p.lookup_size = 0;
00452 p.fast_approx = false;
00453 p.source = 0;
00454 p.temporary = 0;
00455 p.counter = 0;
00456 p.tile = p.tile_border = p.thread = p.nb_threads = 0;
00457 p.stop_request = false;
00458 greycstoration_mutex_destroy(p);
00459 }
00460 p.is_running = false;
00461
00462 if (p.nb_threads) {
00463 #if cimg_OS==1 && defined(_PTHREAD_H)
00464 pthread_exit(arg);
00465 return arg;
00466 #elif cimg_OS==2
00467 ExitThread(0);
00468 #endif
00469 }
00470 return 0;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 #endif