Chan-Vese Segmentation
chanvese.c
Go to the documentation of this file.
1 
19 #include <math.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include "chanvese.h"
25 
26 #define Malloc(s) malloc(s)
27 #define Free(p) free(p)
28 
29 #define DIVIDE_EPS ((num)1e-16)
30 
31 #ifndef M_PI
32 
33 #define M_PI 3.14159265358979323846264338327950288
34 #endif
35 
36 
39 {
40  num Tol;
41  int MaxIter;
42  num Mu;
43  num Nu;
44  num Lambda1;
45  num Lambda2;
46  num dt;
47  int (*PlotFun)(int, int, num, const num*, const num*, const num*,
48  int, int, int, void*);
49  void *PlotParam;
50 };
51 
52 #ifdef __GNUC__
53 int ChanVeseSimplePlot(int State, int Iter, num Delta,
54  const num *c1, const num *c2,
55  __attribute__((unused)) const num *Phi,
56  __attribute__((unused)) int Width,
57  __attribute__((unused)) int Height,
58  int NumChannels,
59  __attribute__((unused)) void *Param);
60 #else
61 int ChanVeseSimplePlot(int State, int Iter, num Delta,
62  const num *c1, const num *c2,
63  const num *Phi,
64  int Width,
65  int Height,
66  int NumChannels,
67  void *Param);
68 #endif
69 
72  {(num)1e-3, 500, (num)0.25, 0, 1, 1, (num)0.5,
73  ChanVeseSimplePlot, NULL};
74 
75 
127 int ChanVese(num *Phi, const num *f,
128  int Width, int Height, int NumChannels, const chanveseopt *Opt)
129 {
130  int (*PlotFun)(int, int, num, const num*, const num*, const num*,
131  int, int, int, void*);
132  const long NumPixels = ((long)Width) * ((long)Height);
133  const long NumEl = NumPixels * NumChannels;
134  const num *fPtr, *fPtr2;
135  double PhiDiffNorm, PhiDiff;
136  num *PhiPtr, *c1 = 0, *c2 = 0;
137  num c1Scalar, c2Scalar, Mu, Nu, Lambda1, Lambda2, dt;
138  num PhiLast, Delta, PhiX, PhiY, IDivU, IDivD, IDivL, IDivR;
139  num Temp1, Temp2, Dist1, Dist2, PhiTol;
140  int Iter, i, j, Channel, MaxIter, Success = 2;
141  int iu, id, il, ir;
142 
143  if(!Phi || !f || Width <= 0 || Height <= 0 || NumChannels <= 0)
144  return 0;
145 
146  if(!Opt)
147  Opt = &DefaultChanVeseOpt;
148 
149  Mu = Opt->Mu;
150  Nu = Opt->Nu;
151  Lambda1 = Opt->Lambda1;
152  Lambda2 = Opt->Lambda2;
153  dt = Opt->dt;
154  MaxIter = Opt->MaxIter;
155  PlotFun = Opt->PlotFun;
156  PhiTol = Opt->Tol;
157  PhiDiffNorm = (PhiTol > 0) ? PhiTol*1000 : 1000;
158 
159  if(NumChannels > 1)
160  {
161  if(!(c1 = Malloc(sizeof(num)*NumChannels))
162  || !(c2 = Malloc(sizeof(num)*NumChannels)))
163  return 0;
164  }
165  else
166  {
167  c1 = &c1Scalar;
168  c2 = &c2Scalar;
169  }
170 
171  RegionAverages(c1, c2, Phi, f, Width, Height, NumChannels);
172 
173  if(PlotFun)
174  if(!PlotFun(0, 0, PhiDiffNorm, c1, c2, Phi,
175  Width, Height, NumChannels, Opt->PlotParam))
176  goto Done;
177 
178  for(Iter = 1; Iter <= MaxIter; Iter++)
179  {
180  PhiPtr = Phi;
181  fPtr = f;
182  PhiDiffNorm = 0;
183 
184  for(j = 0; j < Height; j++)
185  {
186  iu = (j == 0) ? 0 : -Width;
187  id = (j == Height - 1) ? 0 : Width;
188 
189  for(i = 0; i < Width; i++, PhiPtr++, fPtr++)
190  {
191  il = (i == 0) ? 0 : -1;
192  ir = (i == Width - 1) ? 0 : 1;
193 
194  Delta = dt/(M_PI*(1 + PhiPtr[0]*PhiPtr[0]));
195  PhiX = PhiPtr[ir] - PhiPtr[0];
196  PhiY = (PhiPtr[id] - PhiPtr[iu])/2;
197  IDivR = (num)(1/sqrt(DIVIDE_EPS + PhiX*PhiX + PhiY*PhiY));
198  PhiX = PhiPtr[0] - PhiPtr[il];
199  IDivL = (num)(1/sqrt(DIVIDE_EPS + PhiX*PhiX + PhiY*PhiY));
200  PhiX = (PhiPtr[ir] - PhiPtr[il])/2;
201  PhiY = PhiPtr[id] - PhiPtr[0];
202  IDivD = (num)(1/sqrt(DIVIDE_EPS + PhiX*PhiX + PhiY*PhiY));
203  PhiY = PhiPtr[0] - PhiPtr[iu];
204  IDivU = (num)(1/sqrt(DIVIDE_EPS + PhiX*PhiX + PhiY*PhiY));
205 
206  if(NumChannels == 1)
207  {
208  Dist1 = fPtr[0] - c1Scalar;
209  Dist2 = fPtr[0] - c2Scalar;
210  Dist1 *= Dist1;
211  Dist2 *= Dist2;
212  }
213  else
214  {
215  Dist1 = Dist2 = 0.0;
216 
217  for(Channel = 0, fPtr2 = fPtr;
218  Channel < NumChannels; Channel++, fPtr2 += NumPixels)
219  {
220  Temp1 = fPtr2[0] - c1[Channel];
221  Temp2 = fPtr2[0] - c2[Channel];
222  Dist1 += Temp1*Temp1;
223  Dist2 += Temp2*Temp2;
224  }
225  }
226 
227  /* Semi-implicit update of phi at the current point */
228  PhiLast = PhiPtr[0];
229  PhiPtr[0] = (PhiPtr[0] + Delta*(
230  Mu*(PhiPtr[ir]*IDivR + PhiPtr[il]*IDivL
231  + PhiPtr[id]*IDivD + PhiPtr[iu]*IDivU)
232  - Nu - Lambda1*Dist1 + Lambda2*Dist2) ) /
233  (1 + Delta*Mu*(IDivR + IDivL + IDivD + IDivU));
234  PhiDiff = (PhiPtr[0] - PhiLast);
235  PhiDiffNorm += PhiDiff * PhiDiff;
236  }
237  }
238 
239  PhiDiffNorm = sqrt(PhiDiffNorm/NumEl);
240  RegionAverages(c1, c2, Phi, f, Width, Height, NumChannels);
241 
242  if(Iter >= 2 && PhiDiffNorm <= PhiTol)
243  break;
244 
245  if(PlotFun)
246  if(!PlotFun(0, Iter, PhiDiffNorm, c1, c2, Phi,
247  Width, Height, NumChannels, Opt->PlotParam))
248  goto Done;
249  }
250 
251  Success = (Iter <= MaxIter) ? 1:2;
252 
253  if(PlotFun)
254  PlotFun(Success, (Iter <= MaxIter) ? Iter:MaxIter,
255  PhiDiffNorm, c1, c2, Phi,
256  Width, Height, NumChannels, Opt->PlotParam);
257 
258 Done:
259  if(NumChannels > 1)
260  {
261  Free(c2);
262  Free(c1);
263  }
264 
265  return Success;
266 }
267 
268 
270 void ChanVeseInitPhi(num *Phi, int Width, int Height)
271 {
272  int i, j;
273 
274  for(j = 0; j < Height; j++)
275  for(i = 0; i < Width; i++)
276  *(Phi++) = (num)(sin(i*M_PI/5.0)*sin(j*M_PI/5.0));
277 }
278 
279 
281 void RegionAverages(num *c1, num *c2, const num *Phi, const num *f,
282  int Width, int Height, int NumChannels)
283 {
284  const long NumPixels = ((long)Width) * ((long)Height);
285  num Sum1 = 0, Sum2 = 0;
286  long n;
287  long Count1 = 0, Count2 = 0;
288  int Channel;
289 
290  for(Channel = 0; Channel < NumChannels; Channel++, f += NumPixels)
291  {
292  for(n = 0; n < NumPixels; n++)
293  if(Phi[n] >= 0)
294  {
295  Count1++;
296  Sum1 += f[n];
297  }
298  else
299  {
300  Count2++;
301  Sum2 += f[n];
302  }
303 
304  c1[Channel] = (Count1) ? (Sum1/Count1) : 0;
305  c2[Channel] = (Count2) ? (Sum2/Count2) : 0;
306  }
307 }
308 
309 
310 
311 /* If GNU C language extensions are available, apply the "unused" attribute
312  to avoid warnings. TvRestoreSimplePlot is a plotting callback function
313  for TvRestore, so the unused arguments are indeed required. */
314 #ifdef __GNUC__
315 int ChanVeseSimplePlot(int State, int Iter, num Delta,
316  const num *c1, const num *c2,
317  __attribute__((unused)) const num *Phi,
318  __attribute__((unused)) int Width,
319  __attribute__((unused)) int Height,
320  int NumChannels,
321  __attribute__((unused)) void *Param)
322 #else
323 int ChanVeseSimplePlot(int State, int Iter, num Delta,
324  const num *c1, const num *c2,
325  const num *Phi,
326  int Width,
327  int Height,
328  int NumChannels,
329  void *Param)
330 #endif
331 {
332  switch(State)
333  {
334  case 0: /* ChanVese is running */
335  /* We print to stderr so that messages are displayed on the console
336  immediately, during the ChanVese computation. If we use stdout,
337  messages might be buffered and not displayed until after ChanVese
338  completes, which would defeat the point of having this real-time
339  plot callback. */
340  if(NumChannels == 1)
341  fprintf(stderr, " Iteration %4d Delta %7.4f c1 = %6.4f c2 = %6.4f\r",
342  Iter, Delta, *c1, *c2);
343  else
344  fprintf(stderr, " Iteration %4d Delta %7.4f\r", Iter, Delta);
345  break;
346  case 1: /* Converged successfully */
347  fprintf(stderr, "Converged in %d iterations. \n",
348  Iter);
349  break;
350  case 2: /* Maximum iterations exceeded */
351  fprintf(stderr, "Maximum number of iterations exceeded. \n");
352  break;
353  }
354  return 1;
355 }
356 
357 
358 /*
359  * Functions for options handling
360  */
361 
370 {
371  chanveseopt *Opt;
372 
373  if((Opt = (chanveseopt *)Malloc(sizeof(struct chanvesestruct))))
374  *Opt = DefaultChanVeseOpt;
375 
376  return Opt;
377 }
378 
379 
382 {
383  if(Opt)
384  Free(Opt);
385 }
386 
387 
389 void ChanVeseSetMu(chanveseopt *Opt, num Mu)
390 {
391  if(Opt)
392  Opt->Mu = Mu;
393 }
394 
395 
397 void ChanVeseSetNu(chanveseopt *Opt, num Nu)
398 {
399  if(Opt)
400  Opt->Nu = Nu;
401 }
402 
403 
405 void ChanVeseSetLambda1(chanveseopt *Opt, num Lambda1)
406 {
407  if(Opt)
408  Opt->Lambda1 = Lambda1;
409 }
410 
411 
413 void ChanVeseSetLambda2(chanveseopt *Opt, num Lambda2)
414 {
415  if(Opt)
416  Opt->Lambda2 = Lambda2;
417 }
418 
419 
421 void ChanVeseSetTol(chanveseopt *Opt, num Tol)
422 {
423  if(Opt)
424  Opt->Tol = Tol;
425 }
426 
427 
429 void ChanVeseSetDt(chanveseopt *Opt, num dt)
430 {
431  if(Opt)
432  Opt->dt = dt;
433 }
434 
435 
437 void ChanVeseSetMaxIter(chanveseopt *Opt, int MaxIter)
438 {
439  if(Opt)
440  Opt->MaxIter = MaxIter;
441 }
442 
443 
484  int (*PlotFun)(int, int, num, const num*, const num*, const num*,
485  int, int, int, void*), void *PlotParam)
486 {
487  if(Opt)
488  {
489  Opt->PlotFun = PlotFun;
490  Opt->PlotParam = PlotParam;
491  }
492 }
493 
494 
495 void ChanVesePrintOpt(const chanveseopt *Opt)
496 {
497  if(!Opt)
498  Opt = &DefaultChanVeseOpt;
499 
500  printf("tol : %g\n", Opt->Tol);
501  printf("max iter : %d\n", Opt->MaxIter);
502  printf("mu : %g\n", Opt->Mu);
503  printf("nu : %g\n", Opt->Nu);
504  printf("lambda1 : %g\n", Opt->Lambda1);
505  printf("lambda2 : %g\n", Opt->Lambda2);
506  printf("dt : %g\n", Opt->dt);
507 }