77 puts(
"Image coarsening utility, P. Getreuer 2010-2011\n");
78 puts(
"Usage: imcoarsen [options] <input file> <output file>\n\n"
81 puts(
" -x <number> the coarsening factor (>= 1.0, may be non-integer)");
82 puts(
" -p <number> sigma_h, blur size of the Gaussian point spread");
83 puts(
" function in units of output pixels.");
84 puts(
" -b <ext> boundary handling extension, choices for <ext> are");
85 puts(
" const constant extension");
86 puts(
" hsym half-sample symmetric (default)");
87 puts(
" wsym whole-sample symmetric");
88 puts(
" per periodic");
89 puts(
" -g <grid> grid to use for resampling, choices for <grid> are");
90 puts(
" centered grid with centered alignment (default)");
91 puts(
" topleft the top-left anchored grid\n");
93 puts(
" -q <number> quality for saving JPEG images (0 to 100)\n");
95 puts(
"Example: coarsen by factor 2.5");
96 puts(
" imcoarsen -x 2.5 -p 0.35 frog.bmp coarse.bmp");
100 int main(
int argc,
char *argv[])
103 image u = {NULL, 0, 0}, v = {NULL, 0, 0};
125 printf(
"%dx%d input -> %dx%d output\n", u.
Width, u.
Height, v.Width, v.Height);
128 if(!(v.Data = (uint32_t *)
Malloc(
sizeof(uint32_t)*
129 ((
long int)v.Width)*((
long int)v.Height))))
142 printf(
"Output written to \"%s\".\n", Param.
OutputFile);
165 static int ConstExtension(
int N,
int i)
182 static int HSymExtension(
int N,
int i)
202 static int WSymExtension(
int N,
int i)
222 static int PerExtension(
int N,
int i)
237 {ConstExtension, HSymExtension, WSymExtension, PerExtension};
244 const int PsfWidth = 1 + ((PsfRadius == 0) ? 1 : (int)ceil(2*PsfRadius));
245 float *Temp = NULL, *PsfBuf = NULL;
246 float ExpDenom, Weight, Sum[4], DenomSum;
247 float XStart, YStart, X, Y;
249 int IndexX0, IndexY0, SrcOffset, DestOffset;
250 int x, y, n, c, Success = 0;
254 || !(PsfBuf = (
float *)
Malloc(
sizeof(
float)*PsfWidth)))
267 for(x = 0; x < v.
Width; x++)
270 IndexX0 = (
int)ceil(X - PsfRadius - 0.5f);
274 for(n = 0; n < PsfWidth; n++)
276 PsfBuf[n] =
Sqr(X - (IndexX0 + n));
278 if(!n || PsfBuf[n] < DenomSum)
279 DenomSum = PsfBuf[n];
283 for(n = 0; n < PsfWidth; n++)
284 PsfBuf[n] = (
float)exp((DenomSum - PsfBuf[n]) / ExpDenom);
285 else if(IndexX0 == (
int)floor(X - PsfRadius + 0.5f))
291 PsfBuf[0] = PsfBuf[1] = 0.5f;
295 for(n = 0; n < PsfWidth; n++)
296 DenomSum += PsfBuf[n];
298 for(y = 0, SrcOffset = 0, DestOffset = x; y < u.
Height;
299 y++, SrcOffset += u.
Width, DestOffset += v.
Width)
301 Sum[0] = Sum[1] = Sum[2] = Sum[3] = 0;
303 for(n = 0; n < PsfWidth; n++)
306 Pixel = u.
Data[Extension(u.
Width, IndexX0 + n) + SrcOffset];
308 for(c = 0; c < 4; c++)
309 Sum[c] += (
float)((uint8_t *)&Pixel)[c] * Weight;
312 for(c = 0; c < 4; c++)
313 Temp[4*DestOffset + c] = Sum[c] / DenomSum;
320 IndexY0 = (
int)ceil(Y - PsfRadius - 0.5f);
324 for(n = 0; n < PsfWidth; n++)
326 PsfBuf[n] =
Sqr(Y - (IndexY0 + n));
328 if(!n || PsfBuf[n] < DenomSum)
329 DenomSum = PsfBuf[n];
333 for(n = 0; n < PsfWidth; n++)
334 PsfBuf[n] = (
float)exp((DenomSum - PsfBuf[n]) / ExpDenom);
335 else if(IndexY0 == (
int)floor(Y - PsfRadius + 0.5f))
341 PsfBuf[0] = PsfBuf[1] = 0.5f;
345 for(n = 0; n < PsfWidth; n++)
346 DenomSum += PsfBuf[n];
348 for(x = 0; x < v.
Width; x++)
350 Sum[0] = Sum[1] = Sum[2] = Sum[3] = 0;
352 for(n = 0; n < PsfWidth; n++)
354 SrcOffset = x + v.
Width*Extension(u.
Height, IndexY0 + n);
357 for(c = 0; c < 4; c++)
358 Sum[c] += Temp[4*SrcOffset + c] * Weight;
361 for(c = 0; c < 4; c++)
362 ((uint8_t *)&Pixel)[c] = (int)(Sum[c] / DenomSum + 0.5f);
378 static char *DefaultOutputFile = (
char *)
"out.bmp";
399 for(i = 1; i < argc;)
401 if(argv[i] && argv[i][0] ==
'-')
403 if((OptionChar = argv[i][1]) == 0)
410 OptionString = &argv[i][2];
412 OptionString = argv[i];
431 Param->
PsfSigma = (float)atof(OptionString);
435 ErrorMessage(
"Point spread blur size must be nonnegative.\n");
440 if(!strcmp(OptionString,
"const"))
442 else if(!strcmp(OptionString,
"hsym"))
444 else if(!strcmp(OptionString,
"wsym"))
446 else if(!strcmp(OptionString,
"per"))
450 ErrorMessage(
"Boundary extension must be either \"const\", \"hsym\", or \"wsym\".\n");
455 if(!strcmp(OptionString,
"centered")
456 || !strcmp(OptionString,
"center"))
458 else if(!strcmp(OptionString,
"topleft")
459 || !strcmp(OptionString,
"top-left"))
463 ErrorMessage(
"Grid must be either \"centered\" or \"topleft\".\n");
474 ErrorMessage(
"JPEG quality must be between 0 and 100.\n");
483 if(isprint(OptionChar))