Chan-Vese Segmentation
cliio.c
Go to the documentation of this file.
1 
6 #include <ctype.h>
7 #include <math.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "cliio.h"
12 
13 
14 const image NullImage = {NULL, 0, 0, 0};
15 
16 
17 int AllocImageObj(image *f, int Width, int Height, int NumChannels)
18 {
19  if(!f)
20  return 0;
21 
22  if(!(f->Data = (num *)malloc(sizeof(num)*
23  (((size_t)Width)*((size_t)Height))*NumChannels)))
24  {
25  *f = NullImage;
26  return 0;
27  }
28 
29  f->Width = Width;
30  f->Height = Height;
31  f->NumChannels = NumChannels;
32  return 1;
33 }
34 
35 
36 void FreeImageObj(image f)
37 {
38  if(f.Data)
39  free(f.Data);
40 }
41 
42 
43 int ReadImageObj(image *f, const char *FileName)
44 {
45  if(!f || !(f->Data = (num *)ReadImage(&f->Width, &f->Height, FileName,
46  IMAGEIO_NUM | IMAGEIO_RGB | IMAGEIO_PLANAR)))
47  {
48  *f = NullImage;
49  return 0;
50  }
51 
52  f->NumChannels = (IsGrayscale(f->Data, f->Width, f->Height)) ? 1:3;
53  return 1;
54 }
55 
56 
57 int ReadImageObjGrayscale(image *f, const char *FileName)
58 {
59  if(!f || !(f->Data = (num *)ReadImage(&f->Width, &f->Height, FileName,
60  IMAGEIO_NUM | IMAGEIO_GRAYSCALE | IMAGEIO_PLANAR)))
61  {
62  *f = NullImage;
63  return 0;
64  }
65 
66  f->NumChannels = 1;
67  return 1;
68 }
69 
70 
71 int WriteImageObj(image f, const char *FileName, int JpegQuality)
72 {
73  if(!f.Data || !FileName)
74  return 0;
75 
76  switch(f.NumChannels)
77  {
78  case 1:
79  return WriteImage(f.Data, f.Width, f.Height, FileName,
80  IMAGEIO_NUM | IMAGEIO_GRAYSCALE | IMAGEIO_PLANAR, JpegQuality);
81  case 3:
82  return WriteImage(f.Data, f.Width, f.Height, FileName,
83  IMAGEIO_NUM | IMAGEIO_RGB | IMAGEIO_PLANAR, JpegQuality);
84  case 4:
85  return WriteImage(f.Data, f.Width, f.Height, FileName,
86  IMAGEIO_NUM | IMAGEIO_RGBA | IMAGEIO_PLANAR, JpegQuality);
87  default:
88  return 0;
89  }
90 }
91 
92 
94 int IsGrayscale(num *Data, int Width, int Height)
95 {
96  const long NumPixels = ((long)Width) * ((long)Height);
97  const num *Red = Data;
98  const num *Green = Data + NumPixels;
99  const num *Blue = Data + 2*NumPixels;
100  long n;
101 
102  for(n = 0; n < NumPixels; n++)
103  if(Red[n] != Green[n] || Red[n] != Blue[n])
104  return 0;
105 
106  return 1;
107 }
108 
109 
118 int GetStrToken(char *Token, const char *Start, int MaxLength, const char *Delim)
119 {
120  int NumChars = strcspn(Start, Delim);
121  int NumCopy = (NumChars <= MaxLength) ? NumChars : MaxLength;
122 
123  strncpy(Token, Start, NumCopy);
124  Token[NumCopy] = '\0';
125  return NumChars;
126 }
127 
128 
142 int ParseDouble(double *Num, const char *String)
143 {
144  double Accum = 0, Div = 1, Exponent = 0;
145  int i = 0, Sign = 1, ExponentSign = 1;
146  char c;
147 
148 
149  if(!Num || !String)
150  return 0;
151 
152  while(isspace(String[i])) /* Eat leading whitespace */
153  i++;
154 
155  if(String[i] == '-') /* Read sign */
156  {
157  Sign = -1;
158  i++;
159  }
160  else if(String[i] == '+')
161  i++;
162 
163  /* Read one or more digits appearing left of the decimal point */
164  if(isdigit(c = String[i]))
165  Accum = c - '0';
166  else
167  return 0; /* First character is not a digit */
168 
169  while(isdigit(c = String[++i]))
170  Accum = 10*Accum + (c - '0');
171 
172  if(c == '.') /* There is a decimal point */
173  {
174  /* Read zero or more digits appearing right of the decimal point */
175  while(isdigit(c = String[++i]))
176  {
177  Div *= 10;
178  Accum += (c - '0')/Div;
179  }
180  }
181 
182  if(c == 'e' || c == 'E') /* There is an exponent */
183  {
184  i++;
185 
186  if(String[i] == '-') /* Read exponent sign */
187  {
188  ExponentSign = -1;
189  i++;
190  }
191  else if(String[i] == '+')
192  i++;
193 
194  /* Read digits in the exponent */
195  if(isdigit(c = String[i]))
196  {
197  Exponent = c - '0';
198 
199  while(isdigit(c = String[++i]))
200  Exponent = 10*Exponent + (c - '0');
201 
202  Exponent *= ExponentSign;
203  Accum = Accum * pow(10, Exponent);
204  }
205  }
206 
207  Accum *= Sign;
208  *Num = Accum;
209  return i;
210 }
211 
212 
248 int CliParseArglist(const char **Param, const char **Value,
249  char *TokenBuf, int MaxLength, int k, const char *Start,
250  int argc, const char *argv[], const char *Delimiters)
251 {
252  int TokLen, kread = k;
253 
254  *Param = *Value = NULL;
255  TokLen = GetStrToken(TokenBuf, Start, MaxLength, Delimiters);
256 
257  if(TokLen > MaxLength) /* Token is too long */
258  *Value = Start;
259  else
260  {
261  *Param = TokenBuf;
262 
263  /* Check for a non-null character after token (a delimiter)
264  followed by at least one more non-null character. */
265  if(Start[TokLen] && Start[TokLen + 1])
266  *Value = &Start[TokLen + 1];
267  else /* Otherwise, scan ahead for the value */
268  for(kread = k + 1; kread < argc; kread++)
269  if(!argv[kread][0]) /* Null arg */
270  continue;
271  else if(!strchr(Delimiters, argv[kread][0]))
272  {
273  *Value = &argv[kread][0];
274  break;
275  }
276  else if(argv[kread][1])
277  {
278  *Value = &argv[kread][1]; /* Skip first character */
279  break;
280  }
281  }
282 
283  return kread;
284 }
285 
286 
288 int CliGetNum(num *Value, const char *String, const char *Param)
289 {
290  double DoubleValue;
291  int i;
292 
293  if(!Value)
294  {
295  fprintf(stderr, "Null pointer.\n");
296  return 0;
297  }
298  else if(!String)
299  {
300  fprintf(stderr, "Expected a number for %s.\n", Param);
301  return 0;
302  }
303 
304  i = ParseDouble(&DoubleValue, String);
305 
306  if(!i || String[i]) /* No number read, or ends with non-null character */
307  {
308  *Value = 0;
309  fprintf(stderr, "Invalid syntax \"%s\".\n", String);
310  return 0;
311  }
312  else
313  {
314  *Value = (num)DoubleValue;
315  return 1;
316  }
317 }
318 
319 
321 int ReadMatrixFromTextFile(image *f, const char *FileName)
322 {
323  FILE *File;
324  num *Dest = NULL;
325  double Value;
326  long DestNumEl = 0, DestCapacity = 64;
327  int c, Line = 1, Col = 0, NumRows = 0, NumCols = 0;
328 
329  if(!f)
330  return 0;
331 
332  *f = NullImage;
333 
334  if(!(File = fopen(FileName, "rt")))
335  {
336  fprintf(stderr, "Error reading \"%s\":\n", FileName);
337  fprintf(stderr, "Unable to open file.\n");
338  return 0;
339  }
340 
341  /* Allocate an initial destination buffer, it will be resized as needed. */
342  if(!(Dest = (num *)malloc(sizeof(num)*DestCapacity)))
343  goto Catch;
344 
345  while(1)
346  {
347  /* Eat whitespace */
348  do
349  {
350  c = getc(File);
351 
352  if(c == '\n' || c == '\r' || !isspace(c))
353  break;
354  else if(ferror(File))
355  {
356  fprintf(stderr, "Error reading \"%s\".\n", FileName);
357  goto Catch;
358  }
359  }while(!feof(File));
360 
361  if(c == '#')
362  {
363  /* Found a comment, ignore the rest of the line. */
364  do
365  {
366  c = getc(File);
367 
368  if(c == '\n' || c == '\r')
369  break;
370  else if(ferror(File))
371  {
372  fprintf(stderr, "Error reading \"%s\".\n", FileName);
373  goto Catch;
374  }
375  }while(!feof(File));
376  }
377 
378  if(c == EOF || c == '\n' || c == '\r')
379  {
380  if(Col) /* End of a non-empty line */
381  {
382  if(!NumCols)
383  NumCols = Col;
384  else if(NumCols != Col)
385  {
386  fprintf(stderr,
387  "Error reading \"%s\" on line %d:\n"
388  "Rows must have a consistent number of elements.\n",
389  FileName, Line);
390  goto Catch;
391  }
392 
393  NumRows++;
394  Col = 0;
395  }
396 
397  if(c == EOF)
398  break;
399 
400  Line++;
401  }
402  else
403  {
404  /* There should be a number, try to read it. */
405  ungetc(c, File);
406 
407  if(fscanf(File, "%lg", &Value) != 1)
408  {
409  fprintf(stderr,
410  "Error reading \"%s\" on line %d:\nInvalid number.\n",
411  FileName, Line);
412  goto Catch; /* Failed to parse number */
413  }
414 
415  /* Put Value into Dest */
416  if(DestNumEl == DestCapacity)
417  {
418  /* Increase Dest capacity by 10% */
419  DestCapacity += DestCapacity/10 + 1;
420 
421  if(!(Dest = (num *)realloc(Dest, sizeof(num)*DestCapacity)))
422  {
423  fprintf(stderr, "Memory allocation failed.\n");
424  goto Catch;
425  }
426  }
427 
428  Dest[DestNumEl++] = (num)Value;
429  Col++;
430  }
431  }
432 
433  fclose(File);
434  f->Data = Dest;
435  f->Width = NumCols;
436  f->Height = NumRows;
437  f->NumChannels = 1;
438  return 1;
439 Catch:
440  fclose(File);
441  if(Dest)
442  free(Dest);
443  return 0;
444 }
445 
446 
448 int ReadMatrixFromFile(image *f, const char *FileName,
449  int (*RescaleFun)(image *f))
450 {
451  char Type[8];
452 
453  if(!f)
454  return 0;
455 
456  /* If the file is not a known image type, attempt to read it as
457  a text file. */
458  if(!IdentifyImageType(Type, FileName))
459  return ReadMatrixFromTextFile(f, FileName);
460 
461  /* The file appears to be an image type, attempt to read it. */
462  if(!ReadImageObjGrayscale(f, FileName))
463  {
464  fprintf(stderr, "Error reading \"%s\".\n", FileName);
465  return 0;
466  }
467 
468  if(RescaleFun && !RescaleFun(f))
469  {
470  FreeImageObj(*f);
471  *f = NullImage;
472  return 0;
473  }
474 
475  return 1;
476 }