00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <string.h>
00020 #include "libcartoon.h"
00021
00022
00023
00024
00051 void non_linear_cartoon(float * input, float * out, float sigma,
00052 int width, int height)
00053 {
00054
00055 int size = width*height;
00056
00057
00058
00059
00060 int ksize;
00061 float *kernel = fiFloatGaussKernel(sigma,ksize);
00062
00063
00064
00065 float *grad = (float *) malloc(size*sizeof(float));
00066
00067
00068
00069
00070 float *ratio1 = (float *) malloc(size*sizeof(float));
00071 fiComputeImageGradient(input,grad,NULL,width,height);
00072 fiSepConvol(grad,ratio1,width,height, kernel, ksize,kernel,ksize);
00073
00074
00075
00076
00077
00078 float *gconvolved = (float *) malloc(size*sizeof(float));
00079
00080 int niter = 5;
00081 low_pass_filter(input,gconvolved,sigma,niter,width,height);
00082
00083
00084 float *ratio2 = (float *) malloc(size*sizeof(float));
00085 fiComputeImageGradient(gconvolved,grad,NULL,width,height);
00086 fiSepConvol(grad,ratio2,width,height, kernel, ksize,kernel,ksize);
00087
00088
00089
00090
00091
00092
00093
00094 for(int i=0; i < size; i++)
00095 {
00096 float weight = WeightingFunction(ratio1[i] ,ratio2[i]);
00097 out[i] = weight * gconvolved[i] + (1.0 - weight) * input[i];
00098 }
00099
00100
00101 free(ratio1);
00102 free(ratio2);
00103 free(grad);
00104 free(kernel);
00105
00106 free(gconvolved);
00107
00108
00109 }
00110
00111
00112
00113
00114
00129 void non_linear_cartoon(float *ired, float *igreen, float *iblue, float *ored,
00130 float *ogreen, float *oblue, float sigma, int width,
00131 int height)
00132 {
00133
00134 int size = width*height;
00135
00136
00137
00138
00139
00140 int ksize;
00141 float *kernel = fiFloatGaussKernel(sigma,ksize);
00142
00143
00144
00145 float *grad = (float *) malloc(size*sizeof(float));
00146
00147 float *ratioaux = (float *) malloc(size*sizeof(float));
00148 for(int i= 0; i < size; i++) ratioaux[i] = 0;
00149
00150
00151
00152
00153
00154
00155
00156 float *ratio1 = (float *) malloc(size*sizeof(float));
00157
00158
00159 fiComputeImageGradient(ired,grad,NULL,width,height);
00160 fiSepConvol(grad,ratioaux,width,height, kernel, ksize,kernel,ksize);
00161 for(int i= 0; i < size; i++) ratio1[i] = ratioaux[i];
00162
00163 fiComputeImageGradient(igreen,grad,NULL,width,height);
00164 fiSepConvol(grad,ratioaux,width,height, kernel, ksize,kernel,ksize);
00165 for(int i= 0; i < size; i++) ratio1[i] += ratioaux[i];
00166
00167 fiComputeImageGradient(iblue,grad,NULL,width,height);
00168 fiSepConvol(grad,ratioaux,width,height, kernel, ksize,kernel,ksize);
00169 for(int i= 0; i < size; i++) ratio1[i] += ratioaux[i];
00170 for(int i= 0; i < size; i++) ratio1[i] /= 3.0f;
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 int niter=5;
00181 float *ratio2 = (float *) malloc(size*sizeof(float));
00182 float *rconvolved = (float *) malloc(size*sizeof(float));
00183 float *gconvolved = (float *) malloc(size*sizeof(float));
00184 float *bconvolved = (float *) malloc(size*sizeof(float));
00185
00186
00187 low_pass_filter(ired,rconvolved,sigma,niter,width,height);
00188 low_pass_filter(igreen,gconvolved,sigma,niter,width,height);
00189 low_pass_filter(iblue,bconvolved,sigma,niter,width,height);
00190
00191
00192
00193 fiComputeImageGradient(rconvolved,grad,NULL,width,height);
00194 fiSepConvol(grad,ratioaux,width,height, kernel, ksize,kernel,ksize);
00195 for(int i= 0; i < size; i++) ratio2[i] = ratioaux[i];
00196
00197 fiComputeImageGradient(gconvolved,grad,NULL,width,height);
00198 fiSepConvol(grad,ratioaux,width,height, kernel, ksize,kernel,ksize);
00199 for(int i= 0; i < size; i++) ratio2[i] += ratioaux[i];
00200
00201 fiComputeImageGradient(bconvolved,grad,NULL,width,height);
00202 fiSepConvol(grad,ratioaux,width,height, kernel, ksize,kernel,ksize);
00203 for(int i= 0; i < size; i++) ratio2[i] += ratioaux[i];
00204 for(int i= 0; i < size; i++) ratio2[i] /= 3.0f;
00205
00206
00207
00208
00209
00210 for(int i=0; i < size; i++)
00211 {
00212
00213 float weight = WeightingFunction(ratio1[i],ratio2[i]);
00214
00215 ored[i] = weight * rconvolved[i] + (1.0 - weight) * ired[i];
00216 ogreen[i] = weight * gconvolved[i] + (1.0 - weight) * igreen[i];
00217 oblue[i] = weight * bconvolved[i] + (1.0 - weight) * iblue[i];
00218
00219 }
00220
00221
00222
00223
00224
00225 free(ratio1);
00226 free(ratio2);
00227 free(ratioaux);
00228
00229 free(grad);
00230 free(kernel);
00231
00232 free(rconvolved);
00233 free(gconvolved);
00234 free(bconvolved);
00235
00236
00237 }
00238
00239
00240
00241
00242
00261 void low_pass_filter(float * input, float * out, float sigma, int niter,
00262 int width, int height)
00263 {
00264
00265
00266 int size = width*height;
00267
00268
00269 int ksize;
00270 float *kernel = fiFloatGaussKernel(sigma,ksize);
00271
00272
00273
00274 float *imconvolved = (float *) malloc(size*sizeof(float));
00275 float *imdifference = (float *) malloc(size*sizeof(float));
00276
00277
00278
00279 fiSepConvol(input,out,width,height,kernel,ksize,kernel,ksize);
00280
00281
00282 if (niter > 0)
00283 {
00284
00285
00286 fpCombine(input,1.0,out,-1.0,imdifference,width*height);
00287
00288
00289 for(int i=0;i<niter;i++)
00290 {
00291
00292
00293 fiSepConvol(imdifference,imconvolved,width,height,
00294 kernel, ksize,kernel,ksize);
00295
00296
00297 fpCombine(imdifference,1.0,imconvolved,-1.0,
00298 imdifference,width*height);
00299
00300 }
00301
00302
00303
00304 fpCombine(input,1.0,imdifference,-1.0,out,size);
00305
00306
00307 }
00308
00309
00310 free(kernel);
00311 if (imdifference) free(imdifference);
00312 if (imconvolved) free(imconvolved);
00313
00314
00315 }
00316
00317
00318
00319
00320
00334 float WeightingFunction(float r1, float r2)
00335 {
00336
00337
00338 float difference = r1 - r2;
00339
00340 float ar1 = (float) fabs((double) r1);
00341 if (ar1 > 1.0)
00342 difference /= ar1;
00343 else
00344 difference = 0.0;
00345
00346
00347 float weight;
00348 float cmin= 0.25f;
00349 float cmax= 0.50f;
00350
00351 if (difference < cmin)
00352 weight = 0.0;
00353 else if (difference > cmax)
00354 weight = 1.0;
00355 else
00356 weight = (difference - cmin) / (cmax - cmin);
00357
00358
00359 return weight;
00360
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00384 void fpCopy(float *fpI,float *fpO, int iLength)
00385 {
00386 memcpy((void *) fpO, (const void *) fpI, iLength * sizeof(float));
00387 }
00388
00389
00390
00391
00406 void fpCombine(float *u,float a,float *v,float b, float *w, int size)
00407 {
00408 for(int i=0;i<size ;i++) w[i]= (a * u[i] + b* v[i]);
00409
00410 }
00411
00412
00413
00414
00427 void fiComputeImageGradient(float * tpI,float * tpGrad, float * tpOri,
00428 int iWidth, int iHeight)
00429 {
00430
00431
00432 if (!tpI) { printf("Null input image tpI"); exit(-1);}
00433
00434
00435 if (tpGrad) for (int ii = 0; ii < iWidth * iHeight; ii++) tpGrad[ii] = 0.0f;
00436 if (tpOri) for (int ii = 0; ii < iWidth * iHeight; ii++) tpOri[ii] = 0.0f;
00437
00438
00439
00440 for (int ih = 1; ih < iHeight - 1; ih++)
00441 for (int iw = 1; iw < iWidth - 1; iw++) {
00442
00443
00444 float xgrad = tpI[ih * iWidth + iw + 1] -
00445 tpI[ih * iWidth + iw - 1];
00446
00447 float ygrad = tpI[(ih-1) * iWidth + iw] -
00448 tpI[(ih+1) * iWidth + iw];
00449
00450
00451 if (tpGrad)
00452 tpGrad[ih * iWidth + iw] =
00453 sqrtf(xgrad * xgrad + ygrad * ygrad);
00454
00455 if (tpOri)
00456 tpOri[ih * iWidth + iw] = atan2f(-ygrad,xgrad);
00457
00458 }
00459
00460
00461 }
00462
00463
00464
00465
00478 float* fiFloatGaussKernel(float std, int & size)
00479 {
00480
00481
00482
00483 int n = 4 * ceilf(std) + 1;
00484 size = n;
00485
00486
00487 float* u = (float *) malloc(n * sizeof(float));
00488
00489
00490 if (n==1) u[0]=1.0;
00491 else
00492 {
00493
00494 int ishift = (n-1) / 2;
00495
00496 for (int i=ishift; i < n; i++)
00497 {
00498
00499 float v = (float)(i - ishift) / std;
00500
00501 u[i] = u[n-1-i] = (float) exp(-0.5*v*v);
00502
00503 }
00504
00505 }
00506
00507
00508
00509 float fSum = 0.0f;
00510 for (int i=0; i < n; i++) fSum += u[i];
00511 for (int i=0; i < n; i++) u[i] /= fSum;
00512
00513
00514 return u;
00515
00516 }
00517
00518
00519
00520
00521
00532 void fiFloatBufferConvolution(float *buffer,float *kernel,int size,int ksize)
00533 {
00534
00535 for (int i = 0; i < size; i++) {
00536
00537 float sum = 0.0;
00538 float *bp = &buffer[i];
00539 float *kp = &kernel[0];
00540
00541
00542
00543 int k=0;
00544 for(;k + 4 < ksize; bp += 5, kp += 5, k += 5)
00545 sum += bp[0] * kp[0] + bp[1] * kp[1] + bp[2] * kp[2] +
00546 bp[3] * kp[3] + bp[4] * kp[4];
00547
00548
00549 for(; k < ksize; bp++ , kp++, k++) sum += *bp * (*kp);
00550
00551 buffer[i] = sum;
00552 }
00553 }
00554
00555
00556
00569 void fiFloatHorizontalConvolution(float *u, float *v, int width, int height,
00570 float *kernel, int ksize, int boundary)
00571 {
00572
00573 int halfsize = ksize / 2;
00574 int buffersize = width + ksize;
00575 float *buffer = new float[buffersize];
00576
00577 for (int r = 0; r < height; r++) {
00578
00579
00580 int l = r*width;
00581 if (boundary == 1)
00582 for (int i = 0; i < halfsize; i++)
00583 buffer[i] = u[l + halfsize - 1 - i ];
00584 else
00585 for (int i = 0; i < halfsize; i++)
00586 buffer[i] = 0.0;
00587
00588
00589 for (int i = 0; i < width; i++)
00590 buffer[halfsize + i] = u[l + i];
00591
00592
00593 if (boundary == 1)
00594 for (int i = 0; i < halfsize; i++)
00595 buffer[i + width + halfsize] = u[l + width - 1 - i];
00596 else
00597 for (int i = 0; i < halfsize; i++)
00598 buffer[i + width + halfsize] = 0.0;
00599
00600 fiFloatBufferConvolution(buffer, kernel, width, ksize);
00601 for (int c = 0; c < width; c++)
00602 v[r*width+c] = buffer[c];
00603 }
00604
00605
00606 delete[] buffer;
00607 }
00608
00609
00610
00611
00612
00625 void fiFloatVerticalVonvolution(float *u, float *v, int width, int height,
00626 float *kernel,int ksize, int boundary)
00627 {
00628 int halfsize = ksize / 2;
00629 int buffersize = height + ksize;
00630 float *buffer = new float[buffersize];
00631
00632 for (int c = 0; c < width; c++) {
00633
00634 if (boundary == 1)
00635 for (int i = 0; i < halfsize; i++)
00636 buffer[i] = u[(halfsize-i-1)*width + c];
00637 else
00638 for (int i = 0; i < halfsize; i++)
00639 buffer[i] = 0.0f;
00640
00641 for (int i = 0; i < height; i++)
00642 buffer[halfsize + i] = u[i*width + c];
00643
00644 if (boundary == 1)
00645 for (int i = 0; i < halfsize; i++)
00646 buffer[halfsize + height + i] =
00647 u[(height - i - 1)*width+c];
00648 else
00649 for (int i = 0; i < halfsize; i++)
00650 buffer[halfsize + height + i] = 0.0f;
00651
00652 fiFloatBufferConvolution(buffer, kernel, height, ksize);
00653
00654 for (int r = 0; r < height; r++)
00655 v[r*width+c] = buffer[r];
00656
00657 }
00658
00659
00660 delete[] buffer;
00661
00662 }
00663
00664
00665
00683 void fiSepConvol(float *u,float *v,int width,int height,float *xkernel,
00684 int xksize, float *ykernel, int yksize)
00685 {
00686
00687
00688 int boundary = 1;
00689
00690 memcpy(v, u, width*height*sizeof(float));
00691
00692 fiFloatHorizontalConvolution(v, v, width, height, xkernel, xksize,
00693 boundary);
00694 fiFloatVerticalVonvolution(v, v, width, height, ykernel, yksize,
00695 boundary);
00696
00697 }
00698
00699