Image Demosaicking with Contour Stencils
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
mosaic.c
Go to the documentation of this file.
1 
16 #include <string.h>
17 #include <ctype.h>
18 #include "imageio.h"
19 
20 
21 typedef struct
22 {
23  uint32_t *Data;
24  int Width;
25  int Height;
26 } image;
27 
29 typedef struct
30 {
32  char *InputFile;
34  char *OutputFile;
36  int JpegQuality;
38  int RedX;
40  int RedY;
42  int Flatten;
44  int Padding;
46  int ExtraRow;
50  int Verbose;
52 
53 
54 static int ParseParams(programparams *Param, int argc, char *argv[]);
55 
56 
58 static void PrintHelpMessage()
59 {
60  puts("Image mosaicing utility, P. Getreuer 2010-2011\n");
61  puts("Usage: mosaic [options] <input file> <output file>\n\n"
62  "Only " READIMAGE_FORMATS_SUPPORTED " images are supported.\n");
63  puts("Options:");
64  puts(" -p <pattern> CFA pattern, choices for <pattern> are");
65  puts(" RGGB upperleftmost red pixel is at (0,0)");
66  puts(" GRBG upperleftmost red pixel is at (1,0)");
67  puts(" GBRG upperleftmost red pixel is at (0,1)");
68  puts(" BGGR upperleftmost red pixel is at (1,1)\n");
69  puts(" -f Flatten result to a grayscale image");
70  puts(" -r Add one extra row to the top");
71  puts(" -c Add one extra column to the left");
72  puts(" -e <padding> Add <padding> pixels to each border of the image");
73  puts(" -v Verbose output\n");
74 #ifdef USE_LIBJPEG
75  puts(" -q <number> Quality for saving JPEG images (0 to 100)\n");
76 #endif
77  puts("Example: \n"
78  " mosaic -v -p RGGB frog.bmp frog-m.bmp");
79 }
80 
81 
88 static int WSymExtension(int N, int n)
89 {
90  while(1)
91  {
92  if(n < 0)
93  n = -n;
94  else if(n >= N)
95  n = (2*N - 2) - n;
96  else
97  return n;
98  }
99 }
100 
101 
102 int main(int argc, char *argv[])
103 {
104  programparams Param;
105  image u = {NULL, 0, 0}, f = {NULL, 0, 0};
106  uint32_t Pixel;
107  int i, x, y, xOffset, yOffset, Green, Status = 1;
108  int MaxShow = 2;
109  char FillNext = ' ';
110 
111 
112  if(!ParseParams(&Param, argc, argv))
113  return 0;
114 
115  Green = 1 - ((Param.RedX + Param.RedY) & 1);
116 
117  /* Read the input image */
118  if(!(u.Data = (uint32_t *)ReadImage(&u.Width, &u.Height, Param.InputFile,
119  IMAGEIO_U8 | IMAGEIO_RGBA)))
120  goto Catch;
121 
122  f.Width = u.Width + 2*Param.Padding + Param.ExtraColumn;
123  f.Height = u.Height + 2*Param.Padding + Param.ExtraRow;
124 
125  if(!(f.Data = (uint32_t *)Malloc(sizeof(uint32_t)*f.Width*f.Height)))
126  goto Catch;
127 
128  xOffset = Param.Padding + Param.ExtraColumn;
129  yOffset = Param.Padding + Param.ExtraRow;
130 
131  if(Param.Verbose)
132  printf("Resampling with pattern\n\n");
133 
134  /* Mosaic the image */
135  for(y = 0; y < f.Height; y++)
136  for(x = 0; x < f.Width; x++)
137  {
138  Pixel = u.Data[WSymExtension(u.Width, x - xOffset)
139  + u.Width*WSymExtension(u.Height, y - yOffset)];
140 
141  if(Param.Verbose && x <= xOffset + 2 && y <= yOffset + 2)
142  {
143  if((x < MaxShow || x >= xOffset)
144  && (y < MaxShow || y >= yOffset))
145  {
146  if(y == yOffset && x == xOffset)
147  {
148  printf("[");
149  FillNext = ']';
150  }
151  else
152  {
153  printf("%c", FillNext);
154  FillNext = ' ';
155  }
156 
157  if(((x + y) & 1) == Green)
158  printf("G");
159  else if((y & 1) == Param.RedY)
160  printf("R");
161  else
162  printf("B");
163 
164  if(x == xOffset + 2)
165  {
166  if(y == 0 || (yOffset > MaxShow && y == yOffset))
167  printf("...");
168 
169  printf("\n");
170 
171  if(y == MaxShow - 1 && yOffset > MaxShow)
172  {
173  if(xOffset <= MaxShow)
174  i = xOffset + 3;
175  else
176  i = MaxShow + 4;
177 
178  while(i--)
179  printf(" :");
180 
181  printf("\n");
182  }
183  }
184 
185 
186  if(x == MaxShow - 1 && xOffset > MaxShow)
187  {
188  printf("..");
189  FillNext = '.';
190  }
191  }
192  }
193 
194  if(!Param.Flatten)
195  {
196  if(((x + y) & 1) == Green)
197  ((uint8_t *)&Pixel)[0] = ((uint8_t *)&Pixel)[2] = 0;
198  else if((y & 1) == Param.RedY)
199  ((uint8_t *)&Pixel)[1] = ((uint8_t *)&Pixel)[2] = 0;
200  else
201  ((uint8_t *)&Pixel)[0] = ((uint8_t *)&Pixel)[1] = 0;
202  }
203  else
204  {
205  if(((x + y) & 1) == Green)
206  ((uint8_t *)&Pixel)[0] =
207  ((uint8_t *)&Pixel)[2] = ((uint8_t *)&Pixel)[1];
208  else if((y & 1) == Param.RedY)
209  ((uint8_t *)&Pixel)[1] =
210  ((uint8_t *)&Pixel)[2] = ((uint8_t *)&Pixel)[0];
211  else
212  ((uint8_t *)&Pixel)[0] =
213  ((uint8_t *)&Pixel)[1] = ((uint8_t *)&Pixel)[2];
214  }
215 
216  ((uint8_t *)&Pixel)[3] = 255;
217 
218  f.Data[x + f.Width*y] = Pixel;
219  }
220 
221  if(Param.Verbose)
222  {
223  printf(" ... ");
224 
225  if(xOffset > MaxShow)
226  {
227  i = MaxShow - 1;
228 
229  while(i--)
230  printf(" ");
231 
232  printf("...");
233  }
234 
235  printf("\n\n");
236  }
237 
238  /* Write the output image */
239  if(!WriteImage(f.Data, f.Width, f.Height, Param.OutputFile,
240  IMAGEIO_U8 | IMAGEIO_RGBA, Param.JpegQuality))
241  goto Catch;
242  else if(Param.Verbose)
243  printf("Output written to \"%s\".\n", Param.OutputFile);
244 
245  Status = 0;
246 Catch:
247  Free(f.Data);
248  Free(u.Data);
249  return Status;
250 }
251 
252 
253 static int ParseParams(programparams *Param, int argc, char *argv[])
254 {
255  static char *DefaultOutputFile = (char *)"out.bmp";
256  char *OptionString;
257  char OptionChar;
258  int i;
259 
260 
261  if(argc < 2)
262  {
264  return 0;
265  }
266 
267  /* Set parameter defaults */
268  Param->InputFile = 0;
269  Param->OutputFile = DefaultOutputFile;
270  Param->JpegQuality = 100;
271  Param->RedX = 0;
272  Param->RedY = 0;
273  Param->Flatten = 0;
274  Param->Padding = 0;
275  Param->ExtraRow = 0;
276  Param->ExtraColumn = 0;
277  Param->Verbose = 0;
278 
279  for(i = 1; i < argc;)
280  {
281  if(argv[i] && argv[i][0] == '-')
282  {
283  if((OptionChar = argv[i][1]) == 0)
284  {
285  ErrorMessage("Invalid parameter format.\n");
286  return 0;
287  }
288 
289  if(argv[i][2])
290  OptionString = &argv[i][2];
291  else if(++i < argc)
292  OptionString = argv[i];
293  else
294  {
295  ErrorMessage("Invalid parameter format.\n");
296  return 0;
297  }
298 
299  switch(OptionChar)
300  {
301  case 'p':
302  if(!strcmp(OptionString, "RGGB")
303  || !strcmp(OptionString, "rggb"))
304  {
305  Param->RedX = 0;
306  Param->RedY = 0;
307  }
308  else if(!strcmp(OptionString, "GRBG")
309  || !strcmp(OptionString, "grbg"))
310  {
311  Param->RedX = 1;
312  Param->RedY = 0;
313  }
314  else if(!strcmp(OptionString, "GBRG")
315  || !strcmp(OptionString, "gbrg"))
316  {
317  Param->RedX = 0;
318  Param->RedY = 1;
319  }
320  else if(!strcmp(OptionString, "BGGR")
321  || !strcmp(OptionString, "bggr"))
322  {
323  Param->RedX = 1;
324  Param->RedY = 1;
325  }
326  else
327  ErrorMessage("CFA pattern must be RGGB, GRBG, GBRG, or BGGR\n");
328  break;
329  case 'f':
330  Param->Flatten = 1;
331  i--;
332  break;
333  case 'e':
334  Param->Padding = atoi(OptionString);
335 
336  if(Param->Padding < 0)
337  {
338  ErrorMessage("Padding must be nonnegative.\n");
339  return 0;
340  }
341  break;
342  case 'r':
343  Param->ExtraRow = 1;
344  i--;
345  break;
346  case 'c':
347  Param->ExtraColumn = 1;
348  i--;
349  break;
350  case 'v':
351  Param->Verbose = 1;
352  i--;
353  break;
354 
355 #ifdef USE_LIBJPEG
356  case 'q':
357  Param->JpegQuality = atoi(OptionString);
358 
359  if(Param->JpegQuality <= 0 || Param->JpegQuality > 100)
360  {
361  ErrorMessage("JPEG quality must be between 0 and 100.\n");
362  return 0;
363  }
364  break;
365 #endif
366  case '-':
368  return 0;
369  default:
370  if(isprint(OptionChar))
371  ErrorMessage("Unknown option \"-%c\".\n", OptionChar);
372  else
373  ErrorMessage("Unknown option.\n");
374 
375  return 0;
376  }
377 
378  i++;
379  }
380  else
381  {
382  if(!Param->InputFile)
383  Param->InputFile = argv[i];
384  else
385  Param->OutputFile = argv[i];
386 
387  i++;
388  }
389  }
390 
391  if(!Param->InputFile)
392  {
394  return 0;
395  }
396 
397  if(!Param->Verbose)
398  return 1;
399 
400 
401  return 1;
402 }