Total Variation Deconvolution using Split Bregman
tvdeconv.c
Go to the documentation of this file.
1 
21 #include <math.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include "tvreg.h"
25 #include "cliio.h"
26 #include "kernels.h"
27 
28 
30 typedef struct
31 {
33  const char *InputFile;
35  const char *OutputFile;
37  int JpegQuality;
38 
40  num Lambda;
42  image Kernel;
44  const char *Noise;
46 
47 
49 static void PrintHelpMessage()
50 {
51  puts("Total variation deconvolution demo, P. Getreuer 2011-2012\n\n"
52  "Usage: tvdeconv [param:value ...] input output\n\n"
53  "where \"input\" and \"output\" are "
54  READIMAGE_FORMATS_SUPPORTED " files.\n");
55  puts("Parameters");
56  puts(" K:<kernel> blur kernel for deconvolution");
57  puts(" K:disk:<radius> filled disk kernel");
58  puts(" K:gaussian:<sigma> Gaussian kernel");
59  puts(" K:<file> read kernel from text or image file");
60  puts(" lambda:<value> fidelity weight");
61  puts(" noise:<model> noisy model");
62  puts(" noise:gaussian additive Gaussian noise (default)");
63  puts(" noise:laplace Laplace noise");
64  puts(" noise:poisson Poisson noise");
65  puts(" f:<file> input file (alternative syntax)");
66  puts(" u:<file> output file (alternative syntax)");
67 #ifdef USE_LIBJPEG
68  puts(" jpegquality:<number> quality for saving JPEG images (0 to 100)");
69 #endif
70  puts("\nExample: \n"
71  " imblur noise:gaussian:5 K:disk:2 input.bmp blurry.bmp\n");
72 }
73 
74 int TvDeconv(image u, image f, image Kernel, num Lambda, const char *Noise);
75 int ParseParams(programparams *Params, int argc, const char *argv[]);
76 
77 int main(int argc, char **argv)
78 {
79  programparams Params;
80  image f = NullImage, u = NullImage;
81  int Status = 1;
82 
83  if(!ParseParams(&Params, argc, (const char **)argv))
84  goto Catch;
85 
86  /* Read the input image */
87  if(!ReadImageObj(&f, Params.InputFile))
88  goto Catch;
89  else if(!AllocImageObj(&u, f.Width, f.Height, f.NumChannels))
90  {
91  fputs("Out of memory.\n", stderr);
92  goto Catch;
93  }
94 
95  if(!TvDeconv(u, f, Params.Kernel, Params.Lambda, Params.Noise))
96  goto Catch;
97 
98  /* Write the deconvolved image */
99  if(!WriteImageObj(u, Params.OutputFile, Params.JpegQuality))
100  fprintf(stderr, "Error writing to \"%s\".\n", Params.OutputFile);
101 
102  Status = 0;
103 Catch:
104  FreeImageObj(u);
105  FreeImageObj(f);
106  FreeImageObj(Params.Kernel);
107  return Status;
108 }
109 
110 
111 int TvDeconv(image u, image f, image Kernel, num Lambda, const char *Noise)
112 {
113  tvregopt *Opt = NULL;
114  int Success;
115 
116  if(!(Opt = TvRegNewOpt()))
117  {
118  fputs("Out of memory.\n", stderr);
119  return 0;
120  }
121  else if(!(TvRegSetNoiseModel(Opt, Noise)))
122  {
123  fprintf(stderr, "Unknown noise model, \"%s\".\n", Noise);
124  TvRegFreeOpt(Opt);
125  return 0;
126  }
127 
128  memcpy(u.Data, f.Data, sizeof(num)*((size_t)f.Width)
129  *((size_t)f.Height)*f.NumChannels);
130  TvRegSetKernel(Opt, Kernel.Data, Kernel.Width, Kernel.Height);
131  TvRegSetLambda(Opt, Lambda);
132  TvRegSetMaxIter(Opt, 140);
133 
134  if(!(Success = TvRestore(u.Data, f.Data,
135  f.Width, f.Height, f.NumChannels, Opt)))
136  fputs("Error in computation.\n", stderr);
137 
138  TvRegFreeOpt(Opt);
139  return Success;
140 }
141 
142 
144 int ParseParams(programparams *Params, int argc, const char *argv[])
145 {
146  static const char *DefaultOutputFile = (char *)"out.bmp";
147  const char *Param, *Value;
148  num NumValue;
149  char TokenBuf[256];
150  int k, kread, Skip;
151 
152 
153  /* Set parameter defaults */
154  Params->InputFile = NULL;
155  Params->OutputFile = DefaultOutputFile;
156  Params->JpegQuality = 85;
157 
158  Params->Lambda = 20;
159  Params->Kernel = NullImage;
160  Params->Noise = "gaussian";
161 
162  if(argc < 2)
163  {
165  return 0;
166  }
167 
168  k = 1;
169 
170  while(k < argc)
171  {
172  Skip = (argv[k][0] == '-') ? 1 : 0;
173  kread = CliParseArglist(&Param, &Value, TokenBuf, sizeof(TokenBuf),
174  k, &argv[k][Skip], argc, argv, ":");
175 
176  if(!Param)
177  {
178  if(!Params->InputFile)
179  Param = (char *)"f";
180  else
181  Param = (char *)"u";
182  }
183 
184  if(Param[0] == '-') /* Argument begins with two dashes "--" */
185  {
187  return 0;
188  }
189 
190  if(!strcmp(Param, "f") || !strcmp(Param, "input"))
191  {
192  if(!Value)
193  {
194  fprintf(stderr, "Expected a value for option %s.\n", Param);
195  return 0;
196  }
197  Params->InputFile = Value;
198  }
199  else if(!strcmp(Param, "u") || !strcmp(Param, "output"))
200  {
201  if(!Value)
202  {
203  fprintf(stderr, "Expected a value for option %s.\n", Param);
204  return 0;
205  }
206  Params->OutputFile = Value;
207  }
208  else if(!strcmp(Param, "K"))
209  {
210  if(!Value)
211  {
212  fprintf(stderr, "Expected a value for option %s.\n", Param);
213  return 0;
214  }
215  else if(!ReadKernel(&Params->Kernel, Value))
216  return 0;
217  }
218  else if(!strcmp(Param, "lambda"))
219  {
220  if(!CliGetNum(&NumValue, Value, Param))
221  return 0;
222  else if(NumValue <= 0)
223  {
224  fputs("Parameter lambda must be positive.\n", stderr);
225  return 0;
226  }
227  else
228  Params->Lambda = (int)NumValue;
229  }
230  else if(!strcmp(Param, "noise"))
231  {
232  if(!Value)
233  {
234  fprintf(stderr, "Expected a value for option %s.\n", Param);
235  return 0;
236  }
237  else
238  Params->Noise = Value;
239  }
240  else if(!strcmp(Param, "jpegquality"))
241  {
242  if(!CliGetNum(&NumValue, Value, Param))
243  return 0;
244  else if(NumValue < 0 || 100 < NumValue)
245  {
246  fputs("JPEG quality must be between 0 and 100.\n", stderr);
247  return 0;
248  }
249  else
250  Params->JpegQuality = (int)NumValue;
251  }
252  else if(Skip)
253  {
254  fprintf(stderr, "Unknown option \"%s\".\n", Param);
255  return 0;
256  }
257  else
258  {
259  if(!Params->InputFile)
260  Params->InputFile = argv[k];
261  else
262  Params->OutputFile = argv[k];
263 
264  kread = k;
265  }
266 
267  k = kread + 1;
268  }
269 
270  if(!Params->Kernel.Data && !ReadKernel(&Params->Kernel, "disk:0"))
271  return 0;
272 
273  if(!Params->InputFile)
274  {
276  return 0;
277  }
278 
279  return 1;
280 }