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