PTdecode/CImg-1.3.0/examples/greycstoration4gimp.cpp

changeset 5
1204ebf9340d
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/PTdecode/CImg-1.3.0/examples/greycstoration4gimp.cpp	Mon Aug 03 14:09:20 2009 +0100
     1.3 @@ -0,0 +1,649 @@
     1.4 +/*
     1.5 + #
     1.6 + #  File        : greycstoration4gimp.cpp
     1.7 + #                ( C++ source file )
     1.8 + #
     1.9 + #  Description : GREYCstoration - A tool to denoise, inpaint and resize images.
    1.10 + #                ( GIMP>=2.3.4 plug-in version )
    1.11 + #                This file is a part of the CImg Library project.
    1.12 + #                ( http://cimg.sourceforge.net )
    1.13 + #
    1.14 + #    The GREYCstoration algorithm is an implementation of diffusion tensor-directed
    1.15 + #    diffusion PDE's for image regularization and interpolation, published in
    1.16 + #
    1.17 + #    "Fast Anisotropic Smoothing of Multi-Valued Images
    1.18 + #    using Curvature-Preserving PDE's"
    1.19 + #    (D. Tschumperle)
    1.20 + #    International Journal of Computer Vision, May 2006.
    1.21 + #    (see also http://www.greyc.ensicaen.fr/~dtschump/greycstoration)
    1.22 + #
    1.23 + #    "Vector-Valued Image Regularization with PDE's : A Common Framework
    1.24 + #    for Different Applications"
    1.25 + #    (D. Tschumperle, R. Deriche).
    1.26 + #    IEEE Transactions on Pattern Analysis and Machine Intelligence,
    1.27 + #    Vol 27, No 4, pp 506-517, April 2005.
    1.28 + #
    1.29 + #    Copyright  : Grzegorz Szwoch (Original GIMP plugin code)
    1.30 + #                 David Tschumperle (GREYCstoration API)
    1.31 + #                 Nikita Melnichenko (Bugs corrections)
    1.32 + #                 Phillip Wood (Contribution)
    1.33 + #
    1.34 + #    Plug-in version: 1.1
    1.35 + #    Version history:
    1.36 + #         2008.12.05
    1.37 + #        - Support for denoising in YCrCb color space (patch by Phillip Wood)
    1.38 + #    2.9 (2008.06.09)
    1.39 + #        - New version number, following the release number of CImg.
    1.40 + #        - Non-interactive mode allowed (patch by Nikita Melnichenko).
    1.41 + #        - Pdb description parameters re-ordered (patch by Nikita Melnichenko).
    1.42 + #        - Bug correction when dealing with 16 bits image processed in the
    1.43 + #          YUV color space.
    1.44 + #    1.1 (2007.03.31)
    1.45 + #        - Added support for GimpZoomPreview (optional)
    1.46 + #        - Make plug-in work for 1 bpp images
    1.47 + #        - Added button to reset parameters to the initial state
    1.48 + #    1.0 (2007.03.09)
    1.49 + #        - Initial release
    1.50 + #
    1.51 + #  License     : CeCILL v2.0
    1.52 + #                ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    1.53 + #
    1.54 + #  This software is governed by the CeCILL  license under French law and
    1.55 + #  abiding by the rules of distribution of free software.  You can  use,
    1.56 + #  modify and/ or redistribute the software under the terms of the CeCILL
    1.57 + #  license as circulated by CEA, CNRS and INRIA at the following URL
    1.58 + #  "http://www.cecill.info".
    1.59 + #
    1.60 + #  As a counterpart to the access to the source code and  rights to copy,
    1.61 + #  modify and redistribute granted by the license, users are provided only
    1.62 + #  with a limited warranty  and the software's author,  the holder of the
    1.63 + #  economic rights,  and the successive licensors  have only  limited
    1.64 + #  liability.
    1.65 + #
    1.66 + #  In this respect, the user's attention is drawn to the risks associated
    1.67 + #  with loading,  using,  modifying and/or developing or reproducing the
    1.68 + #  software by the user in light of its specific status of free software,
    1.69 + #  that may mean  that it is complicated to manipulate,  and  that  also
    1.70 + #  therefore means  that it is reserved for developers  and  experienced
    1.71 + #  professionals having in-depth computer knowledge. Users are therefore
    1.72 + #  encouraged to load and test the software's suitability as regards their
    1.73 + #  requirements in conditions enabling the security of their systems and/or
    1.74 + #  data to be ensured and,  more generally, to use and operate it in the
    1.75 + #  same conditions as regards security.
    1.76 + #
    1.77 + #  The fact that you are presently reading this means that you have had
    1.78 + #  knowledge of the CeCILL license and that you accept its terms.
    1.79 + #
    1.80 +*/
    1.81 +
    1.82 +/* HOW TO COMPILE THIS PLUG-IN ?
    1.83 + *------------------------------
    1.84 + * g++ -o greycstoration4gimp greycstoration4gimp.cpp `gimptool-2.0 --cflags` `gimptool-2.0 --libs` -lpthread -O3
    1.85 + * Then, copy the file 'greycstoration4gimp' into your GIMP plug-in directory.
    1.86 + */
    1.87 +
    1.88 +//----------------------------------
    1.89 +// Define static plug-in parameters
    1.90 +//----------------------------------
    1.91 +
    1.92 +// Comment the line below if you don't want to use preview with zoom (zoom feature needs GIMP >= 2.3.4)
    1.93 +#define ZOOMPREVIEW
    1.94 +// Uncomment this line to get a rough estimate of how long the plug-in takes to run
    1.95 +// #define TIMER
    1.96 +
    1.97 +// Size of image tiles (in  {0, 256, 512, 1024, 2048})
    1.98 +#define TILESIZE 256
    1.99 +
   1.100 +// Size of tile borders (in [0-16]).
   1.101 +#define TILEBORDER  4
   1.102 +
   1.103 +// Number of simultaneous computation threads (in [1-16]).
   1.104 +// Note : GREYCstoration multi-threading is HIGHLY experimental and may not work on your
   1.105 +//        computer. Please use it only if you checked that all is working correctly !
   1.106 +#define NTHREADS 1
   1.107 +
   1.108 +//-----------------------------------------------------------------------
   1.109 +// Include necessary headers for GIMP, GTK and CImg + GREYCstoration API
   1.110 +//-----------------------------------------------------------------------
   1.111 +#if cimg_OS!=2
   1.112 +#include <pthread.h>
   1.113 +#endif
   1.114 +#define cimg_plugin "plugins/greycstoration.h"
   1.115 +#define cimg_display_type 0
   1.116 +#include <gtk/gtk.h>
   1.117 +#include <libgimp/gimp.h>
   1.118 +#include <libgimp/gimpui.h>
   1.119 +#include "plugins/../CImg.h"
   1.120 +using namespace cimg_library;
   1.121 +
   1.122 +//----------------------------------------------------------
   1.123 +// Define algorithm parameters structure and default values
   1.124 +//----------------------------------------------------------
   1.125 +struct Parameters {
   1.126 +  bool patch_based;     // Select patch-based or non-patch method
   1.127 +
   1.128 +  // Parameters for patch-based method
   1.129 +  gint     patch_size;  // Size of the patches
   1.130 +  gdouble  sigma_p;     // Sigma_p
   1.131 +  gdouble  sigma_s;     // Sigma_s
   1.132 +  gint     lookup_size; // Lookup size
   1.133 +
   1.134 +  // Parameters for non-patch method
   1.135 +  gdouble  amplitude;   // Regularization amplitude
   1.136 +  gdouble  sharpness;   // Contour preservation for regularization (sharpness)
   1.137 +  gdouble  anisotropy;  // Regularization anisotropy
   1.138 +  gdouble  alpha;       // Noise scale
   1.139 +  gdouble  sigma;       // Geometry regularity
   1.140 +  gdouble  dl;          // Spatial integration step for regularization
   1.141 +  gdouble  da;          // Angular integration step for regulatization
   1.142 +  gdouble  gauss_prec;  // Precision of the gaussian function for regularization
   1.143 +  gint     interp;      // Interpolation type
   1.144 +  bool     fast_approx; // Use fast approximation for regularization
   1.145 +  gint     channels;    // Which channels to process
   1.146 +  gint     iterations;  // Number of regularization iterations
   1.147 +  gboolean update_preview;
   1.148 +};
   1.149 +
   1.150 +const Parameters defaults_parameters = {
   1.151 +  false, // patch_based
   1.152 +  4,     // patch_size
   1.153 +  10.0f, // sigma_p
   1.154 +  15.0f, // sigma_s
   1.155 +  7,     // Lookup size
   1.156 +  60.0,  // amplitude
   1.157 +  0.7,   // sharpness
   1.158 +  0.3,   // anisotropy
   1.159 +  0.6,   // alpha
   1.160 +  1.1,   // sigma
   1.161 +  0.8,   // dl
   1.162 +  30.0,  // da
   1.163 +  2.0,   // gauss_prec
   1.164 +  0,     // interp
   1.165 +  true,  // fast_approx
   1.166 +  0,     // process RGB channels
   1.167 +  1,     // iterations
   1.168 +  true   // default is to update the preview
   1.169 +};
   1.170 +
   1.171 +const gint nb_parameters = 20; // Number of parameters + 2
   1.172 +
   1.173 +//---------------------------
   1.174 +// GIMP plug-in declarations
   1.175 +//---------------------------
   1.176 +typedef struct {
   1.177 +  gboolean  run;
   1.178 +} Interface;
   1.179 +
   1.180 +// Plug-in functions
   1.181 +static void query(void);
   1.182 +static void run(const gchar*name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals);
   1.183 +static void process(GimpPixelRgn *srcPTR, GimpPixelRgn *dstPTR, gint bytes, gint x1, gint x2, gint y1, gint y2, gboolean show_progress);
   1.184 +static void callback_response(GtkWidget *widget, gint response_id, gpointer data);
   1.185 +static void run_greycstoration(CImg<unsigned char>& img, const gboolean show_progress);
   1.186 +static gboolean dialog(GimpDrawable *drawable);
   1.187 +static void update_preview(GimpPreview *preview);
   1.188 +
   1.189 +// Plug-in global variables
   1.190 +static gboolean runflag = FALSE;
   1.191 +static Parameters params = defaults_parameters;
   1.192 +GtkWidget *preview;
   1.193 +GtkObject* adj_amplitude;
   1.194 +GtkObject* adj_sharpness;
   1.195 +GtkObject* adj_anisotropy;
   1.196 +GtkObject* adj_alpha;
   1.197 +GtkObject* adj_sigma;
   1.198 +GtkObject* adj_dl;
   1.199 +GtkObject* adj_da;
   1.200 +GtkObject* adj_iterations;
   1.201 +GtkObject* adj_patch_size;
   1.202 +GtkObject* adj_sigma_s;
   1.203 +GtkObject* adj_sigma_p;
   1.204 +GtkObject* adj_lookup_size;
   1.205 +GtkWidget* combo_interp;
   1.206 +GtkWidget* combo_channels;
   1.207 +GtkWidget* button_fast_approx;
   1.208 +GtkWidget* button_patch_based;
   1.209 +CImg<unsigned char> img;
   1.210 +
   1.211 +// Specific GIMP stuffs.
   1.212 +GimpPlugInInfo PLUG_IN_INFO = { 0,0,query,run };  // { init_proc, quit_proc, query_proc, run_proc }
   1.213 +MAIN ()
   1.214 +  static void query(void) {
   1.215 +  static GimpParamDef args[] = {
   1.216 +    {GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive"},
   1.217 +    {GIMP_PDB_IMAGE,    "image", "(unused)"},
   1.218 +    {GIMP_PDB_DRAWABLE, "drawable", "Drawable to draw on"},
   1.219 +    {GIMP_PDB_FLOAT,    "amplitude", "Regularization strength for one iteration"},
   1.220 +    {GIMP_PDB_FLOAT,    "sharpness", "Contour preservation for regularization"},
   1.221 +    {GIMP_PDB_FLOAT,    "anisotropy", "Regularization anisotropy"},
   1.222 +    {GIMP_PDB_FLOAT,    "alpha", "Noise scale"},
   1.223 +    {GIMP_PDB_FLOAT,    "sigma", "Geometry regularity"} ,
   1.224 +    {GIMP_PDB_FLOAT,    "dl", "Spatial integration step for regularization"} ,
   1.225 +    {GIMP_PDB_FLOAT,    "da", "Angular integration step for regulatization"},
   1.226 +    {GIMP_PDB_FLOAT,    "gauss_prec", "Precision of the gaussian function for regularization"},
   1.227 +    {GIMP_PDB_INT8,     "interp", "Interpolation type"},
   1.228 +    {GIMP_PDB_INT32,    "patch_based", "Use patch-based intead of non-patch method"},
   1.229 +    {GIMP_PDB_INT32,    "patch_size", "Size of the patches (for patch-based method)"},
   1.230 +    {GIMP_PDB_FLOAT,    "sigma_p", "Sigma_p (for patch-based method)"},
   1.231 +    {GIMP_PDB_FLOAT,    "sigma_s", "Sigma_s (for patch-based method)"},
   1.232 +    {GIMP_PDB_INT32,    "lookup_size", "Lookup size (for patch-based method)"},
   1.233 +    {GIMP_PDB_INT32,    "fast_approx", "Use fast approximation for regularization"},
   1.234 +    {GIMP_PDB_INT32,    "channels", "Channels to process"},
   1.235 +    {GIMP_PDB_INT32,    "iterations", "Iterations accuracy"}
   1.236 +  };
   1.237 +  gimp_install_procedure ("plug_in_greycstoration",
   1.238 +                          "GREYCstoration Denoising Plugin",
   1.239 +                          "GREYCstoration is an image regularization algorithm which is able to process"
   1.240 +                          " a color image by locally removing small variations of pixel intensities"
   1.241 +                          " while preserving significant global image features, such as edges and corners."
   1.242 +                          " This plugin uses image regularization for image denoising.",
   1.243 +                          "Grzegorz Szwoch & David Tschumperle",
   1.244 +                          "Grzegorz Szwoch & David Tschumperle",
   1.245 +                          "2008-06-02",
   1.246 +                          "_GREYCstoration...",
   1.247 +                          "RGB*, GRAY*",
   1.248 +                          GIMP_PLUGIN,G_N_ELEMENTS(args),0,args, NULL);
   1.249 +  gimp_plugin_menu_register ("plug_in_greycstoration", "<Image>/Filters/Enhance");
   1.250 +}
   1.251 +
   1.252 +//------------------------------
   1.253 +// GIMP plug-in 'run' function
   1.254 +//------------------------------
   1.255 +static void run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) {
   1.256 +  name = 0;
   1.257 +  static GimpParam values[1];
   1.258 +  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
   1.259 +  GimpDrawable *drawable;
   1.260 +  GimpRunMode run_mode;
   1.261 +#ifdef TIMER
   1.262 +  GTimer *timer = g_timer_new ();
   1.263 +#endif
   1.264 +  run_mode = (GimpRunMode)param[0].data.d_int32;
   1.265 +  *return_vals  = values;
   1.266 +  *nreturn_vals = 1;
   1.267 +  values[0].type = GIMP_PDB_STATUS;
   1.268 +  values[0].data.d_status = status;
   1.269 +  //INIT_I18N ();
   1.270 +
   1.271 +  // Get drawable information
   1.272 +  drawable = gimp_drawable_get(param[2].data.d_drawable);
   1.273 +
   1.274 +  // Make tile cache
   1.275 +  gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
   1.276 +
   1.277 +  switch (run_mode) {
   1.278 +  case GIMP_RUN_INTERACTIVE:
   1.279 +    gimp_get_data ("plug_in_greycstoration", &params);    // Reset default values show preview unmodified
   1.280 +    if (!dialog(drawable)) return;
   1.281 +    break;
   1.282 +  case GIMP_RUN_NONINTERACTIVE:
   1.283 +    if (nparams != nb_parameters) { status = GIMP_PDB_CALLING_ERROR; }
   1.284 +    else {
   1.285 +      params.amplitude = param[3].data.d_float;
   1.286 +      params.sharpness = param[4].data.d_float;
   1.287 +      params.anisotropy = param[5].data.d_float;
   1.288 +      params.alpha = param[6].data.d_float;
   1.289 +      params.sigma = param[7].data.d_float;
   1.290 +      params.dl = param[8].data.d_float;
   1.291 +      params.da = param[9].data.d_float;
   1.292 +      params.gauss_prec = param[10].data.d_float;
   1.293 +      params.interp = param[11].data.d_int32;
   1.294 +      params.patch_based = param[12].data.d_int32;
   1.295 +      params.patch_size = param[13].data.d_int32;
   1.296 +      params.sigma_p = param[14].data.d_float;
   1.297 +      params.sigma_s = param[15].data.d_float;
   1.298 +      params.lookup_size = param[16].data.d_int32;
   1.299 +      params.fast_approx = param[17].data.d_int32;
   1.300 +      params.channels = param[18].data.d_int32;
   1.301 +      params.iterations = param[19].data.d_int32;
   1.302 +      if((params.amplitude<0.0) || (params.sharpness<0.0)) status = GIMP_PDB_CALLING_ERROR;
   1.303 +    }
   1.304 +    break;
   1.305 +  case GIMP_RUN_WITH_LAST_VALS:
   1.306 +    gimp_get_data ("plug_in_greycstoration", &params);
   1.307 +    break;
   1.308 +  default:
   1.309 +    break;
   1.310 +  }
   1.311 +
   1.312 +  if(status==GIMP_PDB_SUCCESS) {
   1.313 +    drawable = gimp_drawable_get(param[2].data.d_drawable);
   1.314 +
   1.315 +    // Process image
   1.316 +    GimpPixelRgn srcPR, destPR;
   1.317 +    gint         x1, y1, x2, y2;
   1.318 +
   1.319 +    // Initialize pixel regions
   1.320 +    gimp_pixel_rgn_init(&srcPR,drawable,0,0,drawable->width,drawable->height,false,false);
   1.321 +    gimp_pixel_rgn_init(&destPR,drawable,0,0,drawable->width,drawable->height,true,true);
   1.322 +
   1.323 +    // Get the input
   1.324 +    gimp_drawable_mask_bounds(drawable->drawable_id,&x1,&y1,&x2,&y2);
   1.325 +
   1.326 +    // Process region
   1.327 +    process(&srcPR,&destPR,drawable->bpp,x1,x2,y1,y2,true);
   1.328 +
   1.329 +    // Update image and clean
   1.330 +    gimp_drawable_flush(drawable);
   1.331 +    gimp_drawable_merge_shadow(drawable->drawable_id,true);
   1.332 +    gimp_drawable_update(drawable->drawable_id,x1,y1,x2-x1,y2-y1);
   1.333 +    gimp_displays_flush();
   1.334 +
   1.335 +    // Set data for next use of filter
   1.336 +    gimp_set_data("plug_in_greycstoration",&params,sizeof(Parameters));
   1.337 +    gimp_drawable_detach(drawable);
   1.338 +    values[0].data.d_status = status;
   1.339 +  }
   1.340 +
   1.341 +#ifdef TIMER
   1.342 +  g_printerr("%f seconds\n",g_timer_elapsed(timer,0));
   1.343 +  g_timer_destroy(timer);
   1.344 +#endif
   1.345 +}
   1.346 +
   1.347 +//-----------------------------------
   1.348 +// GIMP plug-in 'process' function
   1.349 +//-----------------------------------
   1.350 +static void process(GimpPixelRgn *srcPR, GimpPixelRgn *destPR, gint bytes, gint x1, gint x2, gint y1, gint y2, gboolean show_progress) {
   1.351 +  gint width  = x2 - x1;
   1.352 +  gint height = y2 - y1;
   1.353 +  guchar* row, *row_ptr;
   1.354 +  if (show_progress) gimp_progress_init("GREYCstoration Filter...");
   1.355 +
   1.356 +  // Make CImg instance and fill it with image information
   1.357 +  const gint channels = (bytes<3)?1:3;
   1.358 +  img.assign(width,height,1,channels,0);
   1.359 +  row = g_new(guchar,width*bytes);
   1.360 +  cimg_forY(img,y) {
   1.361 +    gimp_pixel_rgn_get_row(srcPR,row,x1,y1+y,width);
   1.362 +    row_ptr = row;
   1.363 +    cimg_forX(img,x) { cimg_forV(img,k) img(x,y,k) = row_ptr[k]; row_ptr+=bytes; }
   1.364 +  }
   1.365 +
   1.366 +  // run GREYCstoration processing
   1.367 +  run_greycstoration(img,show_progress);
   1.368 +
   1.369 +  // Write processed image
   1.370 +  cimg_forY(img,y) {
   1.371 +    gimp_pixel_rgn_get_row(srcPR,row,x1,y1+y,width);
   1.372 +    row_ptr = row;
   1.373 +    cimg_forX(img,x) { cimg_forV(img,k) row_ptr[k] = img(x,y,k); row_ptr+=bytes; }
   1.374 +    gimp_pixel_rgn_set_row(destPR,row,x1,y1+y,width);
   1.375 +  }
   1.376 +  g_free(row);
   1.377 +}
   1.378 +
   1.379 +//-----------------------------------------
   1.380 +// Run GREYCstoration process on the image
   1.381 +//-----------------------------------------
   1.382 +static void run_greycstoration(CImg<unsigned char>& img, const gboolean show_progress) {
   1.383 +  guint crange_beg=0, crange_end = img.dimv()-1U;
   1.384 +  if (params.channels && img.dimv() > 1) { // Set up colour model and channel options
   1.385 +    img.RGBtoYCbCr();
   1.386 +    if (params.channels == 1) {
   1.387 +      crange_beg=1;
   1.388 +    } else {
   1.389 +      crange_end=0;
   1.390 +    }
   1.391 +  }
   1.392 +  CImg<unsigned char> img_range = img.get_shared_channels(crange_beg, crange_end);
   1.393 +
   1.394 +  for (gint iter=0; iter<params.iterations; ++iter) {
   1.395 +    if (params.patch_based) img_range.greycstoration_patch_run(params.patch_size,
   1.396 +                                                         params.sigma_p,
   1.397 +                                                         params.sigma_s,
   1.398 +                                                         params.lookup_size,
   1.399 +                                                         params.fast_approx,
   1.400 +                                                         show_progress?TILESIZE:0,
   1.401 +                                                         TILEBORDER,
   1.402 +                                                         show_progress?NTHREADS:1);
   1.403 +    else img_range.greycstoration_run(params.amplitude,
   1.404 +                                params.sharpness,
   1.405 +                                params.anisotropy,
   1.406 +                                params.alpha,
   1.407 +                                params.sigma,
   1.408 +                                1.0f,
   1.409 +                                params.dl,
   1.410 +                                params.da,
   1.411 +                                params.gauss_prec,
   1.412 +                                params.interp,
   1.413 +                                params.fast_approx,
   1.414 +                                show_progress?TILESIZE:0,
   1.415 +                                TILEBORDER,
   1.416 +                                show_progress?NTHREADS:1);
   1.417 +    gint tick = 0;
   1.418 +    do {
   1.419 +      cimg::wait(100);
   1.420 +      ++tick;
   1.421 +      if (tick==10 && show_progress) { // Update progress bar
   1.422 +        const float pr_iteration = img_range.greycstoration_progress();
   1.423 +        const unsigned int pr_global = (unsigned int)((iter*100 + pr_iteration) / params.iterations);
   1.424 +        gimp_progress_update(pr_global/100.0);
   1.425 +        tick = 0;
   1.426 +      }
   1.427 +    } while (img_range.greycstoration_is_running());
   1.428 +  }
   1.429 +  if (params.channels && img.dimv() > 1) { // Convert back to RGB if required
   1.430 +    img.YCbCrtoRGB();
   1.431 +  }
   1.432 +}
   1.433 +
   1.434 +//----------------------
   1.435 +// Update image preview
   1.436 +//----------------------
   1.437 +static void update_preview(GimpPreview *preview) {
   1.438 +#ifdef ZOOMPREVIEW
   1.439 +  // Zoomable style preview
   1.440 +  //-------------------------
   1.441 +  gint width, height, bytes;
   1.442 +  guchar *src, *row_ptr;
   1.443 +  if (img.greycstoration_is_running()) img.greycstoration_stop();
   1.444 +  src = gimp_zoom_preview_get_source(GIMP_ZOOM_PREVIEW(preview),&width,&height,&bytes);
   1.445 +  const gint channels = (bytes<3)?1:3;
   1.446 +  img.assign(width,height,1,channels,0);
   1.447 +  row_ptr = src;
   1.448 +  cimg_forY(img,y) { cimg_forX(img,x) { cimg_forV(img,k) img(x,y,k) = row_ptr[k]; row_ptr += bytes; }}
   1.449 +  run_greycstoration(img,false);
   1.450 +  row_ptr = src;
   1.451 +  cimg_forY(img,y) { cimg_forX(img,x) { cimg_forV(img,k) row_ptr[k] = img(x,y,k); row_ptr += bytes; }}
   1.452 +  gimp_preview_draw_buffer(preview,src,width*bytes);
   1.453 +  g_free(src);
   1.454 +
   1.455 +#else
   1.456 +  // Old style preview (without zoom)
   1.457 +  //----------------------------------
   1.458 +  GimpDrawable *drawable;
   1.459 +  gint x, y, width, height;
   1.460 +  GimpPixelRgn srcPR, destPR;
   1.461 +  drawable = gimp_drawable_preview_get_drawable(GIMP_DRAWABLE_PREVIEW(preview));
   1.462 +  gimp_pixel_rgn_init(&srcPR,drawable,0,0,drawable->width,drawable->height,false,false);
   1.463 +  gimp_pixel_rgn_init(&destPR,drawable,0,0,drawable->width,drawable->height,true,true);
   1.464 +  gimp_preview_get_position(preview,&x,&y);
   1.465 +  gimp_preview_get_size(preview,&width,&height);
   1.466 +  if(img.greycstoration_is_running()) img.greycstoration_stop();
   1.467 +  process(&srcPR,&destPR,drawable->bpp,x,x+width,y,y+height,false);
   1.468 +  gimp_pixel_rgn_init(&destPR,drawable,x,y,width,height,false,true);
   1.469 +  gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(preview),&destPR);
   1.470 +#endif
   1.471 +}
   1.472 +
   1.473 +//----------------------
   1.474 +// Define dialog window
   1.475 +//----------------------
   1.476 +static gboolean dialog (GimpDrawable *drawable) {
   1.477 +  GtkWidget *dialog;
   1.478 +  GtkWidget *main_hbox;
   1.479 +  GtkWidget *table;
   1.480 +
   1.481 +#define SCALE_WIDTH   150
   1.482 +#define ENTRY_WIDTH     4
   1.483 +#define RESPONSE_RESET  1
   1.484 +
   1.485 +  gimp_ui_init("greycstoration",true);
   1.486 +  runflag = false;
   1.487 +  dialog = gimp_dialog_new("GREYCstoration", "greycstoration",0,(GtkDialogFlags)0,gimp_standard_help_func,"plug-in-greycstoration",
   1.488 +                           GIMP_STOCK_RESET,RESPONSE_RESET,GTK_STOCK_CANCEL,GTK_RESPONSE_CANCEL,GTK_STOCK_OK,GTK_RESPONSE_OK,NULL);
   1.489 +  gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),RESPONSE_RESET,GTK_RESPONSE_OK,GTK_RESPONSE_CANCEL,-1);
   1.490 +
   1.491 +#ifdef ZOOMPREVIEW
   1.492 +  gimp_window_set_transient(GTK_WINDOW (dialog));
   1.493 +#endif
   1.494 +
   1.495 +  g_signal_connect(dialog,"response",G_CALLBACK(callback_response),preview);
   1.496 +  g_signal_connect(dialog, "destroy",G_CALLBACK(gtk_main_quit),0);
   1.497 +
   1.498 +  main_hbox = gtk_hbox_new(false,12);
   1.499 +  gtk_container_set_border_width(GTK_CONTAINER(main_hbox),12);
   1.500 +  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),main_hbox);
   1.501 +  gtk_widget_show(main_hbox);
   1.502 +
   1.503 +#ifdef ZOOMPREVIEW
   1.504 +  preview = gimp_zoom_preview_new(drawable);
   1.505 +#else
   1.506 +  preview = gimp_drawable_preview_new(drawable,&params.update_preview);
   1.507 +#endif
   1.508 +  gtk_box_pack_start(GTK_BOX(main_hbox),preview,true,true,0);
   1.509 +  gtk_widget_show(preview);
   1.510 +  g_signal_connect(preview,"invalidated",G_CALLBACK(update_preview),0);
   1.511 +
   1.512 +  table = gtk_table_new(3,3,false);
   1.513 +  gtk_table_set_col_spacings(GTK_TABLE(table),6);
   1.514 +  gtk_table_set_row_spacings(GTK_TABLE(table),6);
   1.515 +  gtk_box_pack_start(GTK_BOX(main_hbox),table,false,false,0);
   1.516 +  gtk_widget_show(table);
   1.517 +
   1.518 +  // 'Amplitude' slider
   1.519 +  adj_amplitude = gimp_scale_entry_new(GTK_TABLE(table),0,0,"_Strength :",SCALE_WIDTH,ENTRY_WIDTH,
   1.520 +                                       params.amplitude,0.0,200.0,1,10,1,true,0,0,0,0);
   1.521 +  g_signal_connect(adj_amplitude,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.amplitude);
   1.522 +  g_signal_connect_swapped(adj_amplitude,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.523 +
   1.524 +  // 'Sharpness' slider
   1.525 +  adj_sharpness = gimp_scale_entry_new(GTK_TABLE(table),0,1,"Contour preser_vation :",SCALE_WIDTH,ENTRY_WIDTH,
   1.526 +                                       params.sharpness,0.0,5.0,0.05,0.5,2,true,0,0,0,0);
   1.527 +  g_signal_connect(adj_sharpness,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.sharpness);
   1.528 +  g_signal_connect_swapped(adj_sharpness,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.529 +
   1.530 +  // 'Anisotropy' slider
   1.531 +  adj_anisotropy = gimp_scale_entry_new(GTK_TABLE(table),0,2,"_Anisotropy :",SCALE_WIDTH,ENTRY_WIDTH,
   1.532 +                                        params.anisotropy,0.0,1.0,0.05,0.5,2,true,0,0,0,0);
   1.533 +  g_signal_connect(adj_anisotropy,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.anisotropy);
   1.534 +  g_signal_connect_swapped(adj_anisotropy,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.535 +
   1.536 +  // 'Alpha' slider
   1.537 +  adj_alpha = gimp_scale_entry_new(GTK_TABLE(table),0,3,"_Noise scale :",SCALE_WIDTH,ENTRY_WIDTH,
   1.538 +                                   params.alpha,0.0,16.0,0.1,0.5, 1,true,0,0,0,0);
   1.539 +  g_signal_connect(adj_alpha,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.alpha);
   1.540 +  g_signal_connect_swapped(adj_alpha,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.541 +
   1.542 +  // 'Sigma' slider
   1.543 +  adj_sigma = gimp_scale_entry_new(GTK_TABLE(table),0,4,"Geometry _regularity :",SCALE_WIDTH,ENTRY_WIDTH,
   1.544 +                                   params.sigma,0,8.0,0.1,0.5,2,true,0,0,0,0);
   1.545 +  g_signal_connect(adj_sigma,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.sigma);
   1.546 +  g_signal_connect_swapped(adj_sigma,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.547 +
   1.548 +  // 'Spatial step' slider
   1.549 +  adj_dl = gimp_scale_entry_new(GTK_TABLE (table),0,5,"Spatial step :",SCALE_WIDTH,ENTRY_WIDTH,
   1.550 +                                params.dl,0.1,1.0,0.01,0.1,2,true,0,0,0,0);
   1.551 +  g_signal_connect(adj_dl,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.dl);
   1.552 +  g_signal_connect_swapped(adj_dl,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.553 +
   1.554 +  // 'Angular step' slider
   1.555 +  adj_da = gimp_scale_entry_new(GTK_TABLE(table),0,6,"Angu_lar step :",SCALE_WIDTH,ENTRY_WIDTH,
   1.556 +                                params.da,1.0,90.0,1.0,10.0,1,true,0,0,0,0);
   1.557 +  g_signal_connect(adj_da,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.da);
   1.558 +  g_signal_connect_swapped(adj_da,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.559 +
   1.560 +  // 'Interpolation' choice
   1.561 +  combo_interp = gimp_int_combo_box_new("Nearest neighbor",0,"Linear",1,"Runge-Kutta",2,NULL);
   1.562 +  gimp_int_combo_box_set_active(GIMP_INT_COMBO_BOX(combo_interp),params.interp);
   1.563 +  gimp_table_attach_aligned(GTK_TABLE(table),0,8,"Interpolation _type :",0.0,0.5,combo_interp,2,false);
   1.564 +  g_signal_connect(combo_interp,"changed",G_CALLBACK(gimp_int_combo_box_get_active),&params.interp);
   1.565 +  g_signal_connect_swapped(combo_interp,"changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.566 +
   1.567 +  // 'Patch-based' button
   1.568 +  button_patch_based = gtk_check_button_new_with_mnemonic("_Patch-based");
   1.569 +  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_patch_based),params.patch_based);
   1.570 +  gimp_table_attach_aligned(GTK_TABLE(table),0,9,"Patch-based :",0.0,0.5,button_patch_based,2,false);
   1.571 +  g_signal_connect(button_patch_based,"toggled",G_CALLBACK(gimp_toggle_button_update),&params.patch_based);
   1.572 +  g_signal_connect_swapped(button_patch_based,"toggled",G_CALLBACK(gimp_preview_invalidate),preview);
   1.573 +
   1.574 +  // 'Patch size' slider
   1.575 +  adj_patch_size = gimp_scale_entry_new(GTK_TABLE(table),0,10,"Patch size :",SCALE_WIDTH,ENTRY_WIDTH,
   1.576 +                                        params.patch_size,1.0,9.0,1.0,1.0,0,true,0,0,0,0);
   1.577 +  g_signal_connect(adj_patch_size,"value_changed",G_CALLBACK(gimp_int_adjustment_update),&params.patch_size);
   1.578 +  g_signal_connect_swapped(adj_patch_size,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.579 +
   1.580 +  // 'Sigma_p' slider
   1.581 +  adj_sigma_p = gimp_scale_entry_new(GTK_TABLE(table),0,11,"_Sigma-p :",SCALE_WIDTH,ENTRY_WIDTH,
   1.582 +                                     params.sigma_p,0.0,30.0,0.1,0.5,1,true,0,0,0,0);
   1.583 +  g_signal_connect(adj_sigma_p,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.sigma_p);
   1.584 +  g_signal_connect_swapped(adj_sigma_p,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.585 +
   1.586 +  // 'Sigma_s' slider
   1.587 +  adj_sigma_s = gimp_scale_entry_new(GTK_TABLE(table),0,12,"_Sigma-s :",SCALE_WIDTH,ENTRY_WIDTH,
   1.588 +                                     params.sigma_s,0.0,30.0,0.1,0.5,1,true,0,0,0,0);
   1.589 +  g_signal_connect(adj_sigma_s,"value_changed",G_CALLBACK(gimp_double_adjustment_update),&params.sigma_s);
   1.590 +  g_signal_connect_swapped(adj_sigma_s,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.591 +
   1.592 +  // 'Lookup size' slider
   1.593 +  adj_lookup_size = gimp_scale_entry_new(GTK_TABLE(table),0,13,"Lookup size :",SCALE_WIDTH,ENTRY_WIDTH,
   1.594 +                                         params.lookup_size,1.0,40.0,1.0,1.0,0,true,0,0,0,0);
   1.595 +  g_signal_connect(adj_lookup_size,"value_changed",G_CALLBACK(gimp_int_adjustment_update),&params.lookup_size);
   1.596 +  g_signal_connect_swapped(adj_lookup_size,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.597 +
   1.598 +  // 'Fast approximation' button
   1.599 +  button_fast_approx = gtk_check_button_new_with_mnemonic("_Enable");
   1.600 +  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_fast_approx),params.fast_approx);
   1.601 +  gimp_table_attach_aligned(GTK_TABLE(table),0,14,"Approximation :",0.0,0.5,button_fast_approx,2,false);
   1.602 +  g_signal_connect(button_fast_approx,"toggled",G_CALLBACK(gimp_toggle_button_update),&params.fast_approx);
   1.603 +  g_signal_connect_swapped(button_fast_approx,"toggled",G_CALLBACK(gimp_preview_invalidate),preview);
   1.604 +
   1.605 +  // 'Channels' choice
   1.606 +  combo_channels = gimp_int_combo_box_new("All",0,"Chroma",1,"Luminance",2,NULL);
   1.607 +  gimp_int_combo_box_set_active(GIMP_INT_COMBO_BOX(combo_channels),params.channels);
   1.608 +  gimp_table_attach_aligned(GTK_TABLE(table),0,15,"Channels",0.0,0.5,combo_channels,2,false);
   1.609 +  g_signal_connect(combo_channels,"changed",G_CALLBACK(gimp_int_combo_box_get_active),&params.channels);
   1.610 +  g_signal_connect_swapped(combo_channels,"changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.611 +  if (drawable->bpp < 3) gtk_widget_set_sensitive(combo_channels, FALSE);
   1.612 +
   1.613 +  // 'Number of iterations' slider
   1.614 +  adj_iterations = gimp_scale_entry_new(GTK_TABLE(table),0,16,"Number of _iterations :",SCALE_WIDTH,ENTRY_WIDTH,
   1.615 +                                        params.iterations,1.0,30.0,1.0,1.0,0,true,0,0,0,0);
   1.616 +  g_signal_connect(adj_iterations,"value_changed",G_CALLBACK(gimp_int_adjustment_update),&params.iterations);
   1.617 +  g_signal_connect_swapped(adj_iterations,"value_changed",G_CALLBACK(gimp_preview_invalidate),preview);
   1.618 +
   1.619 +  // Show dialog window
   1.620 +  gtk_widget_show (dialog);
   1.621 +  gtk_main ();
   1.622 +
   1.623 +  return runflag;
   1.624 +}
   1.625 +
   1.626 +static void callback_response(GtkWidget *widget, gint response_id, gpointer data) {
   1.627 +  data = 0;
   1.628 +  switch (response_id) {
   1.629 +  case RESPONSE_RESET: // Reset parameters to default values & update window
   1.630 +    params = defaults_parameters;
   1.631 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_amplitude), params.amplitude);
   1.632 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_sharpness), params.sharpness);
   1.633 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_anisotropy), params.anisotropy);
   1.634 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_alpha), params.alpha);
   1.635 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_sigma), params.sigma);
   1.636 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_dl), params.dl);
   1.637 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_da), params.da);
   1.638 +    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_iterations), params.iterations);
   1.639 +    gimp_int_combo_box_set_active(GIMP_INT_COMBO_BOX(combo_channels), params.channels);
   1.640 +    gimp_int_combo_box_set_active(GIMP_INT_COMBO_BOX(combo_interp), params.interp);
   1.641 +    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_fast_approx), params.fast_approx);
   1.642 +    gimp_preview_invalidate((GimpPreview*)preview);
   1.643 +    break;
   1.644 +  case GTK_RESPONSE_OK:
   1.645 +    runflag = TRUE;
   1.646 +    gtk_widget_destroy (widget);
   1.647 +    break;
   1.648 +  default:
   1.649 +    gtk_widget_destroy (widget);
   1.650 +    break;
   1.651 +  }
   1.652 +}