00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00080 #include <stdio.h>
00081 #include <stdlib.h>
00082 #include <string.h>
00083 #include <math.h>
00084 #include "io_png/io_png.h"
00085 #include "colorspace/colorspace.h"
00086
00087
00088
00089 unsigned char ScaleAndRound(float X)
00090 {
00091 if (X<=0) {
00092 return 0;
00093 } else if (X>=1) {
00094 return 255;
00095 } else
00096 return (unsigned char)(255.0f*X+0.5f);
00097 }
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 void input2RGB(unsigned char *input,
00110 float **RR, float **GG, float **BB,
00111 int size)
00112 {
00113 float *R, *G, *B;
00114 int n;
00115
00116 R= (float*) malloc(size*sizeof(float));
00117 G= (float*) malloc(size*sizeof(float));
00118 B= (float*) malloc(size*sizeof(float));
00119
00120 for (n=0; n < size; n++) {
00121 R[n]=(float)input[n]/255.0f;
00122 G[n]=(float)input[size+n]/255.0f;
00123 B[n]=(float)input[2*size+n]/255.0f;
00124 }
00125
00126 *RR= R;
00127 *GG= G;
00128 *BB= B;
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138 void RGB2output(float *R, float *G, float *B,
00139 unsigned char *output, int size)
00140 {
00141 int n;
00142
00143 for (n=0; n < size; n++) {
00144 output[n]=ScaleAndRound(R[n]);
00145 output[size+n]=ScaleAndRound(G[n]);
00146 output[2*size+n]=ScaleAndRound(B[n]);
00147 }
00148
00149 }
00150
00151
00152
00153
00154
00155 unsigned char *Im, *Imi;
00156 long Dxy;
00157 int Dx, Dy;
00158
00159
00160
00164 int main(int argc, const char **argv)
00165 {
00166 const char *namein, *nameout;
00167 int radius, option, n, nx, ny, t, nc;
00168 size_t Dxx, Dyy;
00169 unsigned char *img, *output;
00170 float *R, *G, *B, *Rout, *Gout, *Bout;
00171 float *I, *Iout, *Mask, *Mask2, *Pb, *Pr, *H, *S, *Kernel;
00172 float sum, r;
00173 num ii, ppb, ppr, hh, ss, ll, rr, gg, bb;
00174
00175
00176 if (argc < 3) {
00177 printf("Usage: localcolorcorrection input.png output.png \
00178 [radius=40] [option=1]\n");
00179 printf(" option=1: process each color channel separately\n");
00180 printf(" option=2: process intensity channel and add original color \
00181 information\n");
00182 printf(" option=3: process the Luma channel in the YPbPr color \
00183 space\n");
00184 printf(" option=4: process the Luminance channel in the HSL color \
00185 space\n");
00186 return EXIT_FAILURE;
00187 }
00188
00189 radius=40;
00190 option=1;
00191
00192
00193
00194
00195
00196
00197 namein = argv[1];
00198 nameout = argv[2];
00199 if (argc > 3) sscanf(argv[3], "%i", &radius);
00200 if (argc > 4) sscanf(argv[4], "%i", &option);
00201
00202 if (option!=1&&option!=2&&option!=3&&option!=4){
00203 return EXIT_FAILURE;
00204 }
00205
00206
00207 img = read_png_u8_rgb(namein, &Dxx, &Dyy);
00208 Dx=(int) Dxx;
00209 Dy=(int) Dyy;
00210
00211 input2RGB(img, &R, &G, &B, Dx*Dy);
00212
00213 I= (float*) malloc(Dx*Dy*sizeof(float));
00214 Mask= (float*) malloc(Dx*Dy*sizeof(float));
00215 Mask2= (float*) malloc(Dx*Dy*sizeof(float));
00216
00217 Pb=NULL;
00218 Pr=NULL;
00219 H=NULL;
00220 S=NULL;
00221 Iout=NULL;
00222
00223 switch (option) {
00224 case 3:
00225 Pb= (float*) malloc(Dx*Dy*sizeof(float));
00226 Pr= (float*) malloc(Dx*Dy*sizeof(float));
00227
00228 for (n=0; n < Dx*Dy; n++) {
00229 Rgb2Ypbpr(&ii, &ppb, &ppr, R[n], G[n], B[n]);
00230 I[n]=ii;
00231 Pb[n]=ppb;
00232 Pr[n]=ppr;
00233 }
00234 break;
00235 case 4:
00236 H= (float*) malloc(Dx*Dy*sizeof(float));
00237 S= (float*) malloc(Dx*Dy*sizeof(float));
00238
00239 for (n=0; n < Dx*Dy; n++) {
00240 Rgb2Hsl(&hh, &ss, &ll, R[n], G[n], B[n]);
00241 H[n]=hh;
00242 S[n]=ss;
00243 I[n]=ll;
00244 }
00245 break;
00246
00247 default:
00248 for (n=0; n < Dx*Dy; n++) {
00249 I[n]= (R[n]+ G[n]+B[n])/3.0f;
00250 }
00251 break;
00252 }
00253
00254
00255 for (n=0; n < Dx*Dy; n++) {
00256 Mask[n] = I[n];
00257 Mask2[n] =Mask[n];
00258 }
00259
00260
00261 Kernel =(float*) malloc((2*radius+1)*sizeof(float));
00262
00263 if (radius > 0) {
00264 for (n=0; n< 2*radius+1; n++)
00265 Kernel[n] =
00266 (float) exp((double)(-2.0f*(-radius+n)*(-radius+n)/(radius*radius)));
00267
00268 sum=0.0f;
00269 for (n=0; n< 2*radius+1; n++)
00270 sum = sum+Kernel[n];
00271 for (n=0; n< 2*radius+1; n++)
00272 Kernel[n]=(float) (Kernel[n]/sum);
00273
00274
00275
00276 if (radius<Dx/2&&radius<Dy/2) {
00277
00278 for (nx=0; nx<Dx; nx++) {
00279 for (ny=0; ny<Dy; ny++) {
00280 sum=0.0f;
00281 for (t=-radius; t<=radius; t++) {
00282 if (nx+t>=Dx)
00283 sum = sum+Mask[2*Dx-2-nx-t+ny*Dx]*Kernel[t+radius];
00284 else
00285 sum = sum+Mask[abs(nx+t)+ny*Dx]*Kernel[t+radius];
00286 }
00287 Mask2[nx+ny*Dx]=(float) sum;
00288 }
00289 }
00290
00291
00292 for (ny=0; ny<Dy; ny++)
00293 for (nx=0; nx<Dx; nx++) {
00294 sum=0.0f;
00295 for (t=-radius; t<=radius; t++) {
00296 if (ny+t>=Dy)
00297 sum = sum+Mask2[nx+(2*Dy-2-ny-t)*Dx]*
00298 Kernel[t+radius];
00299 else
00300 sum = sum+Mask2[nx+abs(ny+t)*Dx]*
00301 Kernel[t+radius];
00302 }
00303 Mask[nx+ny*Dx]=(float) sum;
00304 }
00305 } else {
00306
00307 for (ny=0; ny<Dy; ny++) {
00308 for (nx=0; nx<Dx; nx++) {
00309 sum = sum+Mask[nx+ny*Dx];
00310 }
00311 }
00312 sum=sum/(Dx*Dy);
00313 for (ny=0; ny<Dy; ny++) {
00314 for (nx=0; nx<Dx; nx++) {
00315 Mask[nx+ny*Dx] = sum;
00316 }
00317 }
00318 }
00319 }
00320
00321
00322 Rout=(float*) malloc(Dx*Dy*sizeof(float));
00323 Gout=(float*) malloc(Dx*Dy*sizeof(float));
00324 Bout=(float*) malloc(Dx*Dy*sizeof(float));
00325
00326 if (option!=1)
00327 Iout=(float*) malloc(Dx*Dy*sizeof(float));
00328
00329 for (n=0; n < Dx*Dy; n++) {
00330 Mask[n]=(float) (2*Mask[n]-1);
00331 Mask[n]=(float) pow(2.0,(double)Mask[n]);
00332
00333 if (option==1) {
00334 Rout[n]=(float) pow((double)R[n],(double)Mask[n]);
00335 Gout[n]=(float) pow((double)G[n],(double)Mask[n]);
00336 Bout[n]=(float) pow((double)B[n],(double)Mask[n]);
00337
00338 } else {
00339 Iout[n]=(float) pow((double)I[n],(double)Mask[n]);
00340 switch (option) {
00341 case 2:
00342 Iout[n]=(float) pow((double)I[n],(double)Mask[n]);
00343 if (I[n]==0)
00344 r=0;
00345 else
00346 r=Iout[n]/I[n];
00347
00348 rr=r*(float) R[n];
00349 gg=r*(float) G[n];
00350 bb=r*(float) B[n];
00351 if ((rr >= 1) || (gg >= 1) || (bb >= 1)) {
00352 if ((R[n] >= G[n]) && (R[n] >= B[n])) {
00353 r=1/(float) R[n];
00354 }
00355 if ((G[n] >= R[n]) && (G[n] >= B[n])) {
00356 r=1/(float) G[n];
00357 }
00358 if ((B[n] >= R[n]) && (B[n] >= G[n])) {
00359 r=1/(float) B[n];
00360 }
00361 rr=r*(float) R[n];
00362 gg=r*(float) G[n];
00363 bb=r*(float) B[n];
00364 }
00365 Rout[n]=rr;
00366 Gout[n]=gg;
00367 Bout[n]=bb;
00368 break;
00369
00370 case 3:
00371 Ypbpr2Rgb(&rr, &gg, &bb, Iout[n], Pb[n], Pr[n]);
00372 Rout[n]=rr;
00373 Gout[n]=gg;
00374 Bout[n]=bb;
00375 break;
00376
00377 case 4:
00378 Hsl2Rgb(&rr, &gg, &bb, H[n], S[n], Iout[n]);
00379 Rout[n]=rr;
00380 Gout[n]=gg;
00381 Bout[n]=bb;
00382 break;
00383 }
00384 }
00385 }
00386
00387
00388 output=(unsigned char *) malloc(3*Dx*Dy);
00389 RGB2output(Rout, Gout, Bout, output, Dx*Dy);
00390
00391
00392 nc=3;
00393 write_png_u8(nameout, output, Dx, Dy, nc);
00394
00395 free(I) ;
00396 free(Mask) ;
00397 free(Mask2) ;
00398 free(Kernel) ;
00399 free(R);
00400 free(G);
00401 free(B);
00402 free(Rout);
00403 free(Gout);
00404 free(Bout);
00405
00406 if (H) free(H);
00407 if (S) free(S);
00408 if (Pb) free(Pb);
00409 if (Pr) free(Pr);
00410 if (Iout) free(Iout);
00411
00412 free(img);
00413 free(output);
00414
00415 return EXIT_SUCCESS;
00416 }