Wed, 05 Aug 2009 15:02:31 +0100
PTdecode: add support for uncompressed data (NOTE: *NOT* supported by the PT-2450DX)
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 }