25 #define MIN(a,b) (((a) <= (b)) ? (a) : (b))
28 #define _CONCAT(A,B) A ## B
31 #define FFT(S) _CONCAT(fftwf_,S)
33 #define FFT(S) _CONCAT(fftw_,S)
40 typedef enum {NOISE_GAUSSIAN, NOISE_LAPLACE, NOISE_POISSON} noisetype;
64 puts(
"Image blurring utility, P. Getreuer 2011-2012\n\n"
65 "Usage: imblur [param:value ...] input output\n\n"
66 "where \"input\" and \"output\" are "
69 puts(
" K:<kernel> blur kernel for deconvolution");
70 puts(
" K:disk:<radius> filled disk kernel");
71 puts(
" K:gaussian:<sigma> Gaussian kernel");
72 puts(
" K:<file> read kernel from text or image file");
73 puts(
" noise:<model>:<sigma> simulate noise with standard deviation sigma");
74 puts(
" noise:gaussian:<sigma> additive white Gaussian noise");
75 puts(
" noise:laplace:<sigma> Laplace noise");
76 puts(
" noise:poisson:<sigma> Poisson noise");
77 puts(
" f:<file> input file (alternative syntax)");
78 puts(
" u:<file> output file (alternative syntax)");
80 puts(
" jpegquality:<number> quality for saving JPEG images (0 to 100)");
83 " imblur noise:gaussian:5 K:disk:2 input.bmp blurry.bmp\n");
104 x = (2*Width - 1) - x;
114 y = (2*Height - 1) - y;
119 return Data[x + ((long)Width)*y];
133 const num *Src,
int SrcWidth,
int SrcHeight,
136 const int PadXOffset = (PadWidth - SrcWidth)/2;
137 const int PadYOffset = (PadHeight - SrcHeight)/2;
138 const long TransNumPixels = ((long)(PadWidth/2 + 1))*((
long)PadHeight);
140 FFT(plan) Plan = NULL;
146 fprintf(stderr,
"Memory allocation failed.\n");
151 if(!(Plan = FFT(plan_dft_r2c_2d)(PadHeight, PadWidth, PadTemp,
152 Dest, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
154 fprintf(stderr,
"FFTW plan creation failed.\n");
161 const int SrcHalfWidth = SrcWidth/2;
162 const int SrcHalfHeight = SrcHeight/2;
164 for(y = 0; y < SrcWidth; y++)
165 for(x = 0; x < SrcHeight; x++)
166 PadTemp[x + ((
long)PadWidth)*y] = 0;
168 for(y = 0; y < SrcHeight; y++)
169 for(x = 0; x < SrcWidth; x++)
170 PadTemp[((x < SrcHalfWidth) ?
171 (PadWidth - SrcHalfWidth + x) : (x - SrcHalfWidth))
172 + ((
long)PadWidth)*((y < SrcHalfHeight) ?
173 (PadHeight - SrcHalfHeight + y) : (y - SrcHalfHeight))]
174 = Src[x + SrcWidth*y];
177 for(y = 0; y < PadHeight; y++)
178 for(x = 0; x < PadWidth; x++)
179 PadTemp[x + ((
long)PadWidth)*y]
181 x - PadXOffset, y - PadYOffset);
184 FFT(destroy_plan)(Plan);
199 num *PadTemp,
int PadWidth,
int PadHeight,
numcomplex *Src)
201 const int PadXOffset = (PadWidth - DestWidth)/2;
202 const int PadYOffset = (PadHeight - DestHeight)/2;
203 FFT(plan) Plan = NULL;
207 if(!(Plan = FFT(plan_dft_c2r_2d)(PadHeight, PadWidth,
208 Src, PadTemp, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
210 fprintf(stderr,
"FFTW plan creation failed.\n");
215 FFT(destroy_plan)(Plan);
217 PadTemp += PadXOffset + PadWidth*PadYOffset;
219 for(y = 0; y < DestHeight; y++, Dest += DestWidth, PadTemp += PadWidth)
220 for(x = 0; x < DestWidth; x++)
221 Dest[x] = PadTemp[x];
235 int BlurImage(num *Image,
int ImageWidth,
int ImageHeight,
int NumChannels,
236 const num *Kernel,
int KernelWidth,
int KernelHeight)
238 const int ImageNumPixels = ImageWidth*ImageHeight;
244 int PadWidth, PadHeight, PadNumPixels;
246 int i, x, y, Channel, Success = 0;
249 if(!Image || !Kernel || !ImageWidth || !ImageHeight)
251 else if(KernelWidth*KernelHeight <= 1)
255 PadWidth = 2*ImageWidth;
256 PadHeight = 2*ImageHeight;
257 PadNumPixels = PadWidth*PadHeight;
259 while(PadWidth < KernelWidth)
260 PadWidth += 2*ImageWidth;
261 while(PadHeight < KernelHeight)
262 PadHeight += 2*KernelHeight;
265 TransWidth = PadWidth/2 + 1;
268 if(!(PadTemp = (num *)FFT(malloc)(
sizeof(num)*PadNumPixels)))
270 fprintf(stderr,
"Memory allocation failed.\n");
276 Kernel, KernelWidth, KernelHeight, 1)))
279 for(Channel = 0; Channel < NumChannels; Channel++)
283 Image + Channel*ImageNumPixels,
284 ImageWidth, ImageHeight, 0)))
287 for(y = i = 0; y < PadHeight; y++)
288 for(x = 0; x < TransWidth; x++, i++)
290 G[0] = KernelFourier[i][0]/PadNumPixels;
291 G[1] = KernelFourier[i][1]/PadNumPixels;
294 Temp = G[0]*ImageFourier[i][0] - G[1]*ImageFourier[i][1];
295 ImageFourier[i][1] = G[0]*ImageFourier[i][1]
296 + G[1]*ImageFourier[i][0];
297 ImageFourier[i][0] = Temp;
301 ImageWidth, ImageHeight,
302 PadTemp, PadWidth, PadHeight, ImageFourier))
309 FFT(free)(KernelFourier);
311 FFT(free)(ImageFourier);
332 for(i = 0; i < NumEl; i++)
339 for(i = 0; i < NumEl; i++)
348 for(i = 0; i < NumEl; i++)
352 a = Sigma * Sigma / ((Mean > 0) ? Mean : (0.5/255));
354 for(i = 0; i < NumEl; i++)
362 int main(
int argc,
char **argv)
368 if(!
ParseParams(&Params, argc, (
const char **)argv))
383 if(Params.
Sigma != 0)
390 fprintf(stderr,
"Error writing to \"%s\".\n", Params.
OutputFile);
395 FreeImageObj(Params.
Kernel);
403 const char *ColonPtr;
407 if(!(ColonPtr = strchr(String,
':'))
408 || (Length = (
int)(ColonPtr - String)) > 9)
411 strncpy(NoiseName, String, Length);
412 NoiseName[Length] =
'\0';
413 Params->
Sigma = (num)atof(ColonPtr + 1);
414 Params->
Sigma /= 255;
416 if(Params->
Sigma < 0)
418 fputs(
"Noise standard deviation must be nonnegative.\n", stderr);
422 if(!strcmp(NoiseName,
"Gaussian") || !strcmp(NoiseName,
"gaussian"))
424 else if(!strcmp(NoiseName,
"Laplace") || !strcmp(NoiseName,
"laplace"))
426 else if(!strcmp(NoiseName,
"Poisson") || !strcmp(NoiseName,
"poisson"))
430 fprintf(stderr,
"Unknown noise model, \"%s\".\n", NoiseName);
441 static const char *DefaultOutputFile = (
char *)
"out.bmp";
442 const char *Param, *Value;
455 Params->
Kernel = NullImage;
467 Skip = (argv[k][0] ==
'-') ? 1 : 0;
469 k, &argv[k][Skip], argc, argv,
":");
485 if(!strcmp(Param,
"f") || !strcmp(Param,
"input"))
489 fprintf(stderr,
"Expected a value for option %s.\n", Param);
494 else if(!strcmp(Param,
"u") || !strcmp(Param,
"output"))
498 fprintf(stderr,
"Expected a value for option %s.\n", Param);
503 else if(!strcmp(Param,
"K"))
507 fprintf(stderr,
"Expected a value for option %s.\n", Param);
513 else if(!strcmp(Param,
"noise"))
517 fprintf(stderr,
"Expected a value for option %s.\n", Param);
523 else if(!strcmp(Param,
"jpegquality"))
527 else if(NumValue < 0 || 100 < NumValue)
529 fprintf(stderr,
"JPEG quality must be between 0 and 100.\n");
537 fprintf(stderr,
"Unknown option \"%s\".\n", Param);