PTdecode/CImg-1.3.0/examples/greycstoration.cpp

Mon, 03 Aug 2009 23:41:04 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 03 Aug 2009 23:41:04 +0100
changeset 11
69416826d18c
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

added dep/*.d and obj/*.o to hgignore

     1 /*
     2  #
     3  #  File        : greycstoration.cpp
     4  #                ( C++ source file )
     5  #
     6  #  Description : GREYCstoration - A tool to denoise, inpaint and resize images.
     7  #                This file is a part of the CImg Library project.
     8  #                ( http://cimg.sourceforge.net )
     9  #                See also the GREYCstoration web page
    10  #                ( http://www.greyc.ensicaen.fr/~dtschump/greycstoration )
    11  #
    12  #    The GREYCstoration algorithm is an implementation of tensor-directed and
    13  #    patch-based diffusion PDE's for image regularization and interpolation,
    14  #    published in
    15  #
    16  #    "Defining Some Variational Methods on the Space of Patches :
    17  #     Application to Multi-Valued Image Denoising and Registration"
    18  #    (D. Tschumperle, L. Brun)
    19  #    Rapport de recherche : Les cahiers du GREYC No 08-01, Mars 2008.
    20  #
    21  #    "Fast Anisotropic Smoothing of Multi-Valued Images
    22  #    using Curvature-Preserving PDE's"
    23  #    (D. Tschumperle)
    24  #    International Journal of Computer Vision, May 2006.
    25  #
    26  #    "Vector-Valued Image Regularization with PDE's : A Common Framework
    27  #    for Different Applications"
    28  #    (D. Tschumperle, R. Deriche).
    29  #    IEEE Transactions on Pattern Analysis and Machine Intelligence,
    30  #    Vol 27, No 4, pp 506-517, April 2005.
    31  #
    32  #  Copyright   : David Tschumperle
    33  #                ( http://www.greyc.ensicaen.fr/~dtschump/ )
    34  #
    35  #  License     : CeCILL v2.0
    36  #                ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    37  #
    38  #  This software is governed by the CeCILL  license under French law and
    39  #  abiding by the rules of distribution of free software.  You can  use,
    40  #  modify and/ or redistribute the software under the terms of the CeCILL
    41  #  license as circulated by CEA, CNRS and INRIA at the following URL
    42  #  "http://www.cecill.info".
    43  #
    44  #  As a counterpart to the access to the source code and  rights to copy,
    45  #  modify and redistribute granted by the license, users are provided only
    46  #  with a limited warranty  and the software's author,  the holder of the
    47  #  economic rights,  and the successive licensors  have only  limited
    48  #  liability.
    49  #
    50  #  In this respect, the user's attention is drawn to the risks associated
    51  #  with loading,  using,  modifying and/or developing or reproducing the
    52  #  software by the user in light of its specific status of free software,
    53  #  that may mean  that it is complicated to manipulate,  and  that  also
    54  #  therefore means  that it is reserved for developers  and  experienced
    55  #  professionals having in-depth computer knowledge. Users are therefore
    56  #  encouraged to load and test the software's suitability as regards their
    57  #  requirements in conditions enabling the security of their systems and/or
    58  #  data to be ensured and,  more generally, to use and operate it in the
    59  #  same conditions as regards security.
    60  #
    61  #  The fact that you are presently reading this means that you have had
    62  #  knowledge of the CeCILL license and that you accept its terms.
    63  #
    64 */
    66 #define cimg_plugin "plugins/greycstoration.h"
    67 #ifndef cimg_debug
    68 #if defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
    69  || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
    70 #define cimg_debug 2
    71 #else
    72 #define cimg_debug 1
    73 #endif
    74 #endif
    75 #include "CImg.h"
    76 #if cimg_OS!=2
    77 #include <pthread.h>
    78 #endif
    79 #define gprintf if (verbose) std::fprintf
    80 using namespace cimg_library;
    82 // The lines below are necessary when using a non-standard compiler as visualcpp6.
    83 #ifdef cimg_use_visualcpp6
    84 #define std
    85 #endif
    86 #ifdef min
    87 #undef min
    88 #undef max
    89 #endif
    91 //-----------
    92 // get_geom() : read geometry from a string (for instance '320x256' or '200%x200%').
    93 //-----------
    94 void get_geom(const char *geom, int &geom_w, int &geom_h) {
    95   char tmp[16];
    96   std::sscanf(geom,"%d%7[^0-9]%d%7[^0-9]",&geom_w,tmp,&geom_h,tmp+1);
    97   if (tmp[0]=='%') geom_w=-geom_w;
    98   if (tmp[1]=='%') geom_h=-geom_h;
    99 }
   101 //--------------------------
   102 // GREYCstoration main code
   103 //--------------------------
   104 template<typename T> void greycstoration(int argc, char **argv, T pixel_type) {
   105   pixel_type = (T)0;
   106   cimg_usage(" Open Source Algorithms for Image Denoising and Interpolation.");
   107   cimg_help("-------------------------------------------------------------------------\n"
   108             " GREYCstoration v3.0, by David Tschumperle.                              \n"
   109             " ------------------------------------------------------------------------\n"
   110             " This program allows to denoise, inpaint and resize 2D color images.     \n"
   111             " It is the result of the research work done in the IMAGE group of the    \n"
   112             " GREYC Lab (CNRS, UMR 6072) (http://www.greyc.ensicaen.fr/EquipeImage/)  \n"
   113             " by David Tschumperle (http://www.greyc.ensicaen.fr/~dtschump/). This    \n"
   114             " program has been primarily released to help people processing image data\n"
   115             " and to allow comparisons between regularization algorithms. This is an  \n"
   116             " open source software, distributed within the CImg Library package       \n"
   117             " (http://cimg.sourceforge.net), and submitted to the CeCILL License. If  \n"
   118             " you are interested to distribute it in a closed-source product, please  \n"
   119             " read the licence file carefully. If you are using 'GREYCstored' images  \n"
   120             " in your own publications, be kind to reference the GREYCstoration web   \n"
   121             " site or the related scientific papers. More informations available at : \n"
   122             "            ** http://cimg.sourceforge.net/greycstoration/ **            \n"
   123             "-------------------------------------------------------------------------\n");
   125   // Read Global parameters
   126   //------------------------
   127   cimg_help("  + Global parameters\n    -----------------------");
   128   const char        *restore_mode    = cimg_option("-restore",(char*)0,"Restore image specified after '-restore'");
   129   const char        *inpaint_mode    = cimg_option("-inpaint",(char*)0,"Inpaint image specified after '-inpaint'");
   130   const char        *resize_mode     = cimg_option("-resize",(char*)0,"Resize image specified after '-resize'");
   131   const char        *clean_mode      = cimg_option("-clean",(char*)0,"Clean image specified after '-clean'");
   132   const char        *reference_image = cimg_option("-ref",(char*)0,"Reference image to compare with");
   133   const char         nb_bits         = cimg_option("-bits",8,"Define input value type (8='uchar', 16='ushort', 32='float')");
   134   const unsigned int value_factor    = cimg_option("-fact",0,"Define input value factor (0=auto)");
   135   const float        noise_g         = cimg_option("-ng",0.0f,"Add Gaussian noise before denoising");
   136   const float        noise_u         = cimg_option("-nu",0.0f,"Add Uniform noise before denoising");
   137   const float        noise_s         = cimg_option("-ns",0.0f,"Add Salt&Pepper noise before denoising");
   138   const unsigned int color_base      = cimg_option("-cbase",0,"Processed color base (0=RGB, 1=YCbCr)");
   139   const char        *channel_range   = cimg_option("-crange",(char*)0,"Processed channels (ex: '0-2')");
   140   const unsigned int saving_step     = cimg_option("-save",0,"Iteration saving step (>=0)");
   141   const bool         visu            = cimg_option("-visu",cimg_display?true:false,"Enable/Disable visualization windows (0 or 1)");
   142   const char        *file_o          = cimg_option("-o",(char*)0,"Filename of output image");
   143   const bool         append_result   = cimg_option("-append",false,"Append images in output file");
   144   const bool         verbose         = cimg_option("-verbose",true,"Verbose mode");
   145   const unsigned int jpg_quality     = cimg_option("-quality",100,"Output compression quality (if JPEG format)");
   146   unsigned int       nb_iterations   = cimg_option("-iter",(restore_mode||clean_mode)?1:(inpaint_mode?1000:3),
   147                                                    "Number of iterations (>0)");
   148   const float        sdt             = cimg_option("-sharp",(restore_mode||clean_mode)?0.0f:(inpaint_mode?0.0f:10.0f),
   149                                                    "Sharpening strength (activate sharpening filter, >=0)");
   150   const float        sp              = cimg_option("-se",(restore_mode||clean_mode)?0.5f:(inpaint_mode?0.5f:3.0f),
   151                                                    "Sharpening edge threshold (>=0)");
   152   const unsigned int tile_size       = cimg_option("-tile",512,"Activate tiled mode and set tile size (>=0)");
   153   const unsigned int tile_border     = cimg_option("-btile",4,"Size of tile borders (>=0)");
   154   const unsigned int nb_threads      = cimg_option("-threads",1,"Number of threads used (*experimental*, tile mode only, >0)");
   155   const bool         fast_approx     = cimg_option("-fast",true,"Try faster algorithm (true or false)");
   157   // Declare specific algorithm parameters
   158   //--------------------------------------
   159   float amplitude = 0, sharpness = 0, anisotropy = 0, alpha = 0, sigma = 0, gauss_prec = 0, dl = 0, da = 0, sigma_s = 0, sigma_p = 0;
   160   unsigned int interpolation = 0, patch_size = 0, lookup_size = 0;
   162   if (argc==1 ||
   163       (!restore_mode && !inpaint_mode && !resize_mode && !clean_mode) ||
   164       (restore_mode && inpaint_mode) || (restore_mode && resize_mode) || (restore_mode && clean_mode) ||
   165       (inpaint_mode && resize_mode) || (inpaint_mode && clean_mode)) {
   166     std::fprintf(stderr,"\n%s : You must specify (only) one of the '-restore', '-inpaint', '-resize' or '-clean' options.\n"
   167                  "(try option '-h', '-h -restore','-h -inpaint', '-h -resize' or '-h -clean' to get options relative to specific actions\n\n",
   168                  cimg::basename(argv[0]));
   169     std::exit(0);
   170   }
   172   // Init variables
   173   //----------------
   174   CImg<T> img0, img, imgr;
   175   CImg<unsigned char> mask;
   176   CImgDisplay disp;
   178   // Read specific parameters for image restoration
   179   //------------------------------------------------
   180   if (restore_mode) {
   181     cimg_help("\n  + Restoration mode parameters\n    ---------------------------");
   182     amplitude      = cimg_option("-dt",40.0f,"Regularization strength per iteration (>=0)");
   183     sharpness      = cimg_option("-p",0.9f,"Contour preservation (>=0)");
   184     anisotropy     = cimg_option("-a",0.15f,"Smoothing anisotropy (0<=a<=1)");
   185     alpha          = cimg_option("-alpha",0.6f,"Noise scale (>=0)");
   186     sigma          = cimg_option("-sigma",1.1f,"Geometry regularity (>=0)");
   187     gauss_prec     = cimg_option("-prec",2.0f,"Computation precision (>0)");
   188     dl             = cimg_option("-dl",0.8f,"Spatial integration step (0<=dl<=1)");
   189     da             = cimg_option("-da",30.0f,"Angular integration step (0<=da<=90)");
   190     interpolation  = cimg_option("-interp",0,"Interpolation type (0=Nearest-neighbor, 1=Linear, 2=Runge-Kutta)");
   192     gprintf(stderr,"- Image Restoration mode\n");
   193     if (!cimg::strcmp("-restore",restore_mode)) {
   194       std::fprintf(stderr,"%s : You must specify a valid input image filename after the '-restore' flag.\n\n",cimg::basename(argv[0]));
   195       std::exit(0);
   196     }
   197     gprintf(stderr,"- Load input image '%s'...",cimg::basename(restore_mode));
   198     img.load(restore_mode);
   199     gprintf(stderr,"\r- Input image : '%s' (size %dx%d, value range [%g,%g])\n",
   200             cimg::basename(restore_mode),img.dimx(),img.dimy(),(double)img.min(),(double)img.max());
   201     if (noise_g || noise_u || noise_s) {
   202       img0 = img;
   203       img.noise(noise_g,0).noise(noise_u,1).noise(noise_s,2);
   204       gprintf(stderr,"\r- Noisy image : value range [%g,%g], PSNR Noisy / Original : %g\n",
   205               (double)img.min(),(double)img.max(),img.PSNR(img0));
   206     }
   207   }
   209   // Specific parameters for image inpainting
   210   //-----------------------------------------
   211   if (inpaint_mode) {
   212     cimg_help("\n  + Inpainting mode parameters\n    --------------------------");
   213     const char *file_m        = cimg_option("-m",(char*)0,"Input inpainting mask");
   214     const unsigned int dilate = cimg_option("-dilate",0,"Inpainting mask dilatation (>=0)");
   215     const unsigned int init   = cimg_option("-init",4,"Inpainting init (0=black, 1=white, 2=noise, 3=unchanged, 4=smart)");
   216     amplitude                 = cimg_option("-dt",20.0f,"Regularization strength per iteration (>=0)");
   217     sharpness                 = cimg_option("-p",0.3f,"Contour preservation (>=0)");
   218     anisotropy                = cimg_option("-a",1.0f,"Smoothing anisotropy (0<=a<=1)");
   219     alpha                     = cimg_option("-alpha",0.8f,"Noise scale (>=0)");
   220     sigma                     = cimg_option("-sigma",2.0f,"Geometry regularity (>=0)");
   221     gauss_prec                = cimg_option("-prec",2.0f,"Computation precision (>0)");
   222     dl                        = cimg_option("-dl",0.8f,"Spatial integration step (0<=dl<=1)");
   223     da                        = cimg_option("-da",30.0f,"Angular integration step (0<=da<=90)");
   224     interpolation             = cimg_option("-interp",0,"Interpolation type (0=Nearest-neighbor, 1=Linear, 2=Runge-Kutta)");
   226     gprintf(stderr,"- Image Inpainting mode\n");
   227     if (!cimg::strcmp("-inpaint",inpaint_mode)) {
   228       std::fprintf(stderr,"%s : You must specify a valid input image filename after the '-inpaint' flag.\n\n",
   229                    cimg::basename(argv[0]));
   230       std::exit(0);
   231     }
   232     gprintf(stderr,"- Load input image '%s'...",cimg::basename(inpaint_mode));
   233     img.load(inpaint_mode);
   234     gprintf(stderr,"\r- Input image : '%s' (size %dx%d, value range [%g,%g])\n",
   235             cimg::basename(inpaint_mode),img.dimx(),img.dimy(),(double)img.min(),(double)img.max());
   236     if (noise_g || noise_u || noise_s) {
   237       img0 = img;
   238       img.noise(noise_g,0).noise(noise_u,1).noise(noise_s,2);
   239       gprintf(stderr,"\r- Noisy image : value range [%g,%g], PSNR Noisy / Original : %g\n",
   240               (double)img.min(),(double)img.max(),img.PSNR(img0));
   241     }
   242     if (!file_m) {
   243       std::fprintf(stderr,"%s : You need to specify a valid inpainting mask filename after the '-m' flag.\n\n",
   244                    cimg::basename(argv[0]));
   245       std::exit(0);
   246     }
   247     if (cimg::strncasecmp("block",file_m,5)) {
   248       gprintf(stderr,"- Load inpainting mask '%s'...",cimg::basename(file_m));
   249       mask.load(file_m);
   250       gprintf(stderr,"\r- Inpainting mask : '%s' (size %dx%d)\n",
   251               cimg::basename(file_m),mask.dimx(),mask.dimy());
   252     }
   253     else {
   254       unsigned int l = 16; std::sscanf(file_m,"block%u",&l);
   255       mask.assign(img.dimx()/l,img.dimy()/l);
   256       cimg_forXY(mask,x,y) mask(x,y) = (x+y)%2;
   257       img0 = img;
   258     }
   259     mask.resize(img.dimx(),img.dimy(),1,1);
   260     if (dilate) mask.dilate(dilate);
   261     switch (init) {
   262     case 0 : { cimg_forXYV(img,x,y,k) if (mask(x,y)) img(x,y,k) = 0; } break;
   263     case 1 : { cimg_forXYV(img,x,y,k) if (mask(x,y)) img(x,y,k) = 255; } break;
   264     case 2 : { cimg_forXYV(img,x,y,k) if (mask(x,y)) img(x,y,k) = (T)(255*cimg::rand()); } break;
   265     case 3 : break;
   266     default: {
   267       typedef unsigned char uchar;
   268       CImg<unsigned char> tmask(mask), ntmask(tmask);
   269       CImg_3x3(M,uchar); Mpp = Mnp = Mpn = Mnn = 0;
   270       CImg_3x3(I,T); Ipp = Inp = Icc = Ipn = Inn = 0;
   271       while (ntmask.max()>0) {
   272         cimg_for3x3(tmask,x,y,0,0,M) if (Mcc && (!Mpc || !Mnc || !Mcp || !Mcn)) {
   273           const float
   274             ccp = Mcp?0.0f:1.0f, cpc = Mpc?0.0f:1.0f,
   275             cnc = Mnc?0.0f:1.0f, ccn = Mcn?0.0f:1.0f,
   276             csum = ccp + cpc + cnc + ccn;
   277           cimg_forV(img,k) {
   278             cimg_get3x3(img,x,y,0,k,I);
   279             img(x,y,k) = (T)((ccp*Icp + cpc*Ipc + cnc*Inc + ccn*Icn)/csum);
   280           }
   281           ntmask(x,y) = 0;
   282         }
   283         tmask = ntmask;
   284       }
   285     } break;
   286     }
   287   }
   289   // Specific parameters for image resizing
   290   //----------------------------------------
   291   if (resize_mode) {
   292     cimg_help("\n  + Resizing mode parameters\n    ------------------------");
   293     const char *geom0         = cimg_option("-g0",(char*)0,"Input image geometry");
   294     const char *geom          = cimg_option("-g",(char*)0,"Output image geometry");
   295     const bool anchor         = cimg_option("-anchor",true,"Anchor original pixels (keep their original values)");
   296     const unsigned int init   = cimg_option("-init",3,"Initial estimate (1=block, 3=linear, 4=Moving average, 5=bicubic)");
   297     amplitude                 = cimg_option("-dt",20.0f,"Regularization strength per iteration (>=0)");
   298     sharpness                 = cimg_option("-p",0.2f,"Contour preservation (>=0)");
   299     anisotropy                = cimg_option("-a",0.9f,"Smoothing anisotropy (0<=a<=1)");
   300     alpha                     = cimg_option("-alpha",0.1f,"Noise scale (>=0)");
   301     sigma                     = cimg_option("-sigma",1.5f,"Geometry regularity (>=0)");
   302     gauss_prec                = cimg_option("-prec",2.0f,"Computation precision (>0)");
   303     dl                        = cimg_option("-dl",0.8f,"Spatial integration step (0<=dl<=1)");
   304     da                        = cimg_option("-da",30.0f,"Angular integration step (0<=da<=90)");
   305     interpolation             = cimg_option("-interp",0,"Interpolation type (0=Nearest-neighbor, 1=Linear, 2=Runge-Kutta)");
   307     gprintf(stderr,"- Image Resizing mode\n");
   308     if (!geom && !geom0) {
   309       std::fprintf(stderr,"%s : You need to specify an output geometry or an input geometry (option -g or -g0).\n\n",
   310                    cimg::basename(argv[0]));
   311       std::exit(0);
   312     }
   313     if (!cimg::strcmp("-resize",resize_mode)) {
   314       std::fprintf(stderr,"%s : You must specify a valid input image filename after the '-resize' flag.\n\n",
   315                    cimg::basename(argv[0]));
   316       std::exit(0);
   317     }
   318     gprintf(stderr,"- Load input image '%s'...",cimg::basename(resize_mode));
   319     img.load(resize_mode);
   320     gprintf(stderr,"\r- Input image : '%s' (size %dx%d, value range [%g,%g])\n",
   321             cimg::basename(resize_mode),img.dimx(),img.dimy(),(double)img.min(),(double)img.max());
   322     if (noise_g || noise_u || noise_s) {
   323       img0 = img;
   324       img.noise(noise_g,0).noise(noise_u,1).noise(noise_s,2);
   325       gprintf(stderr,"\r- Noisy image : value range [%g,%g], PSNR Noisy / Original : %g\n",
   326               (double)img.min(),(double)img.max(),img.PSNR(img0));
   327     }
   328     int w, h;
   329     if (geom0) {
   330       int w0, h0;
   331       get_geom(geom0,w0,h0);
   332       w0 = w0>0?w0:-w0*img.dimx()/100;
   333       h0 = h0>0?h0:-h0*img.dimy()/100;
   334       gprintf(stderr,"- Reducing geometry to %dx%d using %s interpolation.\n",w0,h0,
   335               init==1?"bloc":(init==3?"linear":(init==5?"bicubic":"moving average")));
   336       img0.assign(img);
   337       w = img.dimx();
   338       h = img.dimy();
   339       img.resize(w0,h0,-100,-100,5);
   340     }
   341     if (geom) {
   342       get_geom(geom,w,h);
   343       w = w>0?w:-w*img.dimx()/100;
   344       h = h>0?h:-h*img.dimy()/100;
   345     }
   346     mask.assign(img.dimx(),img.dimy(),1,1,255);
   347     if (!anchor) mask.resize(w,h,1,1,1); else mask = !mask.resize(w,h,1,1,4);
   348     img.resize(w,h,1,-100,init);
   349     if (img0) { gprintf(stderr,"\r- PSNR Original / Thumbnail : %g\n",img.PSNR(img0)); }
   350   }
   352   // Specific parameters for image cleaning
   353   //----------------------------------------
   354   if (clean_mode) {
   355     cimg_help("\n  + Cleaning mode parameters\n    ------------------------");
   356     patch_size  = cimg_option("-p",4,"Patch size (>0)");
   357     sigma_s     = cimg_option("-ss",15.0f,"Spatial sigma (>0)");
   358     sigma_p     = cimg_option("-sp",10.0f,"Patch sigma (>0)");
   359     lookup_size = cimg_option("-r",7,"Size of the lookup region (>0)");
   361     gprintf(stderr,"- Image Cleaning mode\n");
   362     if (!cimg::strcmp("-clean",clean_mode)) {
   363       std::fprintf(stderr,"%s : You must specify a valid input image filename after the '-clean' flag.\n\n",
   364                    cimg::basename(argv[0]));
   365       std::exit(0);
   366     }
   367     gprintf(stderr,"- Load input image '%s'...",cimg::basename(clean_mode));
   368     img.load(clean_mode);
   369     gprintf(stderr,"\r- Input image : '%s' (size %dx%d, value range [%g,%g])\n",
   370             cimg::basename(clean_mode),img.dimx(),img.dimy(),(double)img.min(),(double)img.max());
   371     if (noise_g || noise_u || noise_s) {
   372       img0 = img;
   373       img.noise(noise_g,0).noise(noise_u,1).noise(noise_s,2);
   374       gprintf(stderr,"\r- Noisy image : value range [%g,%g], PSNR Noisy / Original : %g\n",
   375               (double)img.min(),(double)img.max(),img.PSNR(img0));
   376     }
   377   }
   379   // Load reference image if any specified
   380   //--------------------------------------
   381   if (reference_image) {
   382     gprintf(stderr,"- Load reference image '%s'...",cimg::basename(reference_image));
   383     imgr.load(reference_image);
   384     gprintf(stderr,"\r- Reference image : '%s' (size %dx%d, value range [%g,%g])",
   385             cimg::basename(reference_image),imgr.dimx(),imgr.dimy(),(double)imgr.min(),(double)imgr.max());
   386     if (img0) { imgr.resize(img0); gprintf(stderr,", PSNR Reference / Original : %g dB\n",imgr.PSNR(img0)); }
   387     else { imgr.resize(img); gprintf(stderr,"\n"); }
   388   }
   390   // Init images and display
   391   //-------------------------
   392   CImg<T> dest(img);
   393   unsigned int crange_beg = 0, crange_end = dest.dimv()-1U;
   394   if (color_base) {
   395     switch (nb_bits) {
   396     case 8: dest.RGBtoYCbCr(); break;
   397     case 16: (dest/=256).RGBtoYCbCr(); break;
   398     default: std::fprintf(stderr,"\n%s : YCbCr color base is not authorized for 32bits float-valued images.\n\n",
   399                           cimg::basename(argv[0])); std::exit(0);
   400     }
   401   }
   402   if (channel_range) std::sscanf(channel_range,"%u%*c%u",&crange_beg,&crange_end);
   403   gprintf(stderr,"- Color base : %s, Channels range : %u-%u\n",color_base?"YCbCr":"RGB",crange_beg,crange_end);
   404   if (!visu && !append_result) img.assign();
   405   if (visu) {
   406     const int sx = 2*CImgDisplay::screen_dimx()/3, sy = 2*CImgDisplay::screen_dimy()/3;
   407     int nwidth = dest.dimx(), nheight = dest.dimy();
   408     if (nwidth>sx) { nheight = nheight*sx/nwidth; nwidth = sx; }
   409     if (nheight>sy) { nwidth = nwidth*sy/nheight; nheight = sy; }
   410     disp.assign(nwidth,nheight,"GREYCstoration");
   411     if (color_base) {
   412       if (nb_bits==16) (dest.get_YCbCrtoRGB()*=256).display(disp);
   413       else dest.get_YCbCrtoRGB().display(disp);
   414     }
   415     else dest.display(disp);
   416   }
   417   const float gfact = (value_factor>0)?value_factor:((sizeof(T)==2)?1.0f/256:1.0f);
   419   //---------------------------------
   420   // Begin GREYCstoration iterations
   421   //---------------------------------
   422   bool stop_all = false;
   423   for (unsigned int iter=0; iter<nb_iterations && !stop_all; iter++) {
   424     bool stop_iteration = false;
   426     // Run one iteration of the GREYCstoration filter
   427     //------------------------------------------------
   428     CImg<T> dest_range = dest.get_shared_channels(crange_beg,crange_end);
   429     if (restore_mode)
   430       dest_range.greycstoration_run(amplitude,sharpness,anisotropy,alpha,sigma,gfact,dl,da,gauss_prec,
   431                                     interpolation,fast_approx,tile_size,tile_border,nb_threads);
   432     if (clean_mode)
   433       dest_range.greycstoration_patch_run(patch_size,sigma_s,sigma_p,lookup_size,
   434                                           tile_size,tile_border,nb_threads,fast_approx);
   435     if (inpaint_mode || resize_mode)
   436       dest_range.greycstoration_run(mask,amplitude,sharpness,anisotropy,alpha,sigma,gfact,dl,da,gauss_prec,
   437                                     interpolation,fast_approx,tile_size,tile_border,nb_threads);
   438     do {
   439       const unsigned int progress = (unsigned int)dest_range.greycstoration_progress();
   440       gprintf(stderr,"\r- Processing : Iteration %u/%u (%u%%)\t\t",1+iter,nb_iterations,progress);
   441       if (disp) {
   442         if (disp.is_resized) disp.resize();
   443         disp.set_title("Processing : Iteration %u/%u (%u%%)",1+iter,nb_iterations,progress);
   444         if (disp.is_closed || disp.is_keyQ || disp.is_keyESC) {
   445           dest_range.greycstoration_stop();
   446           stop_iteration = true;
   447           iter = nb_iterations-1;
   448         }
   449       }
   450       cimg::wait(200);
   451     } while (dest_range.greycstoration_is_running());
   452     if (!stop_iteration && sdt>0) dest_range.sharpen(sdt,sp,alpha/3,sigma/3);
   453     dest_range.cut(cimg::type<T>::min(),cimg::type<T>::max());
   455     // Prepare for next iteration
   456     //---------------------------
   457     CImg<T> tmp_rgb = color_base?(nb_bits==16?dest.get_YCbCrtoRGB()*=256:dest.get_YCbCrtoRGB()):CImg<T>(),
   458       &dest_rgb = color_base?tmp_rgb:dest;
   459     if (disp && visu) dest_rgb.display(disp);
   460     if (file_o && saving_step && !(iter%saving_step)) dest_rgb.save(file_o,iter);
   462     // Display result and allows user interaction if needed.
   463     //-------------------------------------------------------
   464     if (iter==nb_iterations-1) {
   465       gprintf(stderr,"\r- Processing : Done !                          \n");
   466       if (img0) { gprintf(stderr,"- PSNR Restored / Original : %g dB\n",dest_rgb.PSNR(img0)); }
   467       if (disp) {
   468         static bool first_time = true;
   469         if (first_time) {
   470           first_time = false;
   471           gprintf(stderr,
   472                   "- GREYCstoration interface :\n"
   473                   " > You can now zoom to a particular rectangular region,\n"
   474                   "   or press one of the following key on the display window :\n"
   475                   "   SPACE : Swap views.\n"
   476                   "   S     : Save a snapshot of the current image.\n"
   477                   "   I     : Run another iteration.\n"
   478                   "   Q     : Quit GREYCstoration.\n");
   479         }
   481         CImgList<T> visu;
   482         visu.insert(img0,~0,true).insert(img,~0,true).insert(dest_rgb,~0,true).insert(imgr,~0U,true);
   483         const char *titles[4] = { "original", "noisy", "restored", "reference"};
   484         unsigned int visupos = 2;
   485         CImgDisplay dispz;
   486         CImg<T> zoom;
   487         int snb = 0;
   488         bool stop_interact = false;
   489         while (!stop_interact) {
   490           disp.show().set_title("GREYCstoration (%s)",titles[visupos]);
   491           const CImg<int> s = visu(visupos).get_select(disp,2);
   492           if (disp.is_closed) stop_interact = true;
   493           switch (disp.key) {
   494           case cimg::keySPACE: do { visupos = (visupos+1)%visu.size; } while (!visu(visupos)); break;
   495           case cimg::keyBACKSPACE: do { visupos = (visupos-1+visu.size)%visu.size; } while (!visu(visupos)); break;
   496           case cimg::keyQ: stop_interact = stop_all = true; break;
   497           case cimg::keyI:
   498             stop_interact = true;
   499             gprintf(stderr,"- Perform iteration %u...\n",++nb_iterations);
   500             dest_rgb.display(disp);
   501             break;
   502           case cimg::keyS:
   503             if (!snb) {
   504               if (!append_result) dest_rgb.save(file_o?file_o:"GREYCstoration.bmp");
   505               else CImgList<T>(img,dest_rgb).get_append('x').save(file_o?file_o:"GREYCstoration.bmp");
   506             }
   507             if (zoom) zoom.save(file_o?file_o:"GREYCstoration.bmp",snb);
   508             gprintf(stderr,"- Snapshot %u : '%s' saved\n",snb++,file_o?file_o:"GREYCstoration.bmp");
   509             break;
   510           }
   511           disp.key = 0;
   512           if (disp.is_resized) disp.resize().display(visu(visupos));
   513           if (dispz && dispz.is_resized) dispz.resize().display(zoom);
   514           if (dispz && dispz.is_closed) dispz.assign();
   516           if (s[0]>=0 && s[1]>=0 && s[3]>=0 && s[4]>=0) {
   517             const int x0 = s[0], y0 = s[1], x1 = s[3], y1 = s[4];
   518             if (cimg::abs(x0-x1)>4 && cimg::abs(y0-y1)>4) {
   519               CImgList<T> tmp(img.get_crop(x0,y0,x1,y1), dest_rgb.get_crop(x0,y0,x1,y1));
   520               if (img0) tmp.insert(img0.get_crop(x0,y0,x1,y1),0);
   521               if (imgr) tmp.insert(imgr.get_crop(x0,y0,x1,y1));
   522               zoom = tmp.get_append('x','c');
   523               if (!dispz) {
   524                 const int sx = 5*CImgDisplay::screen_dimx()/6, sy = 5*CImgDisplay::screen_dimy()/6;
   525                 int nwidth = zoom.dimx(), nheight = zoom.dimy();
   526                 if (nwidth>nheight) { nheight = nheight*sx/nwidth; nwidth = sx; }
   527                 else { nwidth = nwidth*sy/nheight; nheight = sy; }
   528                 dispz.assign(zoom.get_resize(nwidth,nheight));
   529                 dispz.set_title("GREYCstoration (zoom) : - %s %s %s %s",
   530                                 img0?"original -":"",
   531                                 img?"noisy -":"",
   532                                 dest?"restored -":"",
   533                                 imgr?"reference -":"");
   534               } else dispz.resize(dispz.dimx(),dispz.dimx()*zoom.dimy()/zoom.dimx(),false);
   535               dispz.display(zoom).show();
   536             }
   537           }
   538         }
   539       }
   540     }
   541   }
   543   // Save result and exit
   544   //----------------------
   545   if (file_o) {
   546     CImg<T> tmp_rgb = color_base?(nb_bits==16?dest.get_YCbCrtoRGB()*=256:dest.get_YCbCrtoRGB()):CImg<T>(),
   547       &dest_rgb = color_base?tmp_rgb:dest;
   548     if (jpg_quality) {
   549       gprintf(stderr,"\n- Saving output image '%s' (JPEG quality = %u%%)\n",file_o,jpg_quality);
   550       if (!append_result) dest_rgb.save_jpeg(file_o,jpg_quality);
   551       else CImgList<T>(img,dest_rgb).get_append('x').save_jpeg(file_o,jpg_quality);
   552     } else {
   553       gprintf(stderr,"\n- Saving output image '%s'\n",file_o);
   554       if (!append_result) dest_rgb.save(file_o);
   555       else CImgList<T>(img,dest_rgb).get_append('x').save(file_o);
   556     }
   557   }
   558   gprintf(stderr,"\n- Quit\n\n");
   559 }
   562 /*-----------------
   563   Main procedure
   564   ----------------*/
   565 int main(int argc,char **argv) {
   566   const unsigned int color_base = cimg_option("-cbase",0,0);
   567   switch (cimg_option("-bits",8,0)) {
   568   case 32: { float pixel_type = 0; greycstoration(argc,argv,pixel_type); } break;
   569   case 16: {
   570     if (!color_base) { float pixel_type = 0; greycstoration(argc,argv,pixel_type); }
   571     else { unsigned short pixel_type = 0; greycstoration(argc,argv,pixel_type); }
   572   } break;
   573   default: { unsigned char pixel_type = 0; greycstoration(argc,argv,pixel_type); } break;
   574   }
   575   return 0;
   576 }