PTdecode/CImg-1.3.0/examples/greycstoration.cpp

Wed, 05 Aug 2009 17:32:05 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 05 Aug 2009 17:32:05 +0100
changeset 18
fd1c6f6066da
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

updated README

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