Image Demosaicking with Contour Stencils
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
dmcswl1.c
Go to the documentation of this file.
1 
20 #include <math.h>
21 #include <string.h>
22 #include "basic.h"
23 #include "conv.h"
24 #include "inv3x3.h"
25 #include "dmbilinear.h"
26 #include "mstencils.h"
27 #include "dmcswl1.h"
28 
29 
31 #define GAMMA1 4
32 
33 #define GAMMA2 256
34 
38 #define NUMNEIGH 8
39 
43 #define NUMORIENTATIONS 8
44 
46 #define MU (GAMMA2/(2*NUMNEIGH*GAMMA1))
47 
48 
49 #ifndef DOXYGEN_SHOULD_SKIP_THIS
50 
51 /* Color transformation matrix */
52 #define CMAT_YR (5.773502691896258e-1)
53 #define CMAT_YG (5.773502691896258e-1)
54 #define CMAT_YB (5.773502691896258e-1)
55 #define CMAT_UR (M_1_SQRT2)
56 #define CMAT_UG (0.0)
57 #define CMAT_UB (-M_1_SQRT2)
58 #define CMAT_VR (4.08248290463863e-1)
59 #define CMAT_VG (-8.16496580927726e-1)
60 #define CMAT_VB (4.08248290463863e-1)
61 
62 /* === Construction of inverse matrices ===
63  *
64  * The following performs compile-time evaluation of the 3x3 inverse matrices
65  *
66  * (C^* C + mu e_m^T e_m)^-1,
67  *
68  * where e_m is (1,0,0)^T, (0,1,0)^T, or (0,0,1)^T for m = R, G, B and
69  * mu = gamma_2 / (2 NUMNEIGH gamma_1). The macros UR_, UB_, and UG_
70  * represent the matrices C^* C + mu e_m^T e_m. The actual matrix inverse
71  * computation is done by the INV3X3_ macros defined in inv3x3.h.
72  */
73 
74 /* Compute CCMAT = C^* C */
75 #define CCMAT_RR (CMAT_YR*CMAT_YR + CMAT_UR*CMAT_UR + CMAT_VR*CMAT_VR)
76 #define CCMAT_RG (CMAT_YR*CMAT_YG + CMAT_UR*CMAT_UG + CMAT_VR*CMAT_VG)
77 #define CCMAT_RB (CMAT_YR*CMAT_YB + CMAT_UR*CMAT_UB + CMAT_VR*CMAT_VB)
78 #define CCMAT_GR (CMAT_YG*CMAT_YR + CMAT_UG*CMAT_UR + CMAT_VG*CMAT_VR)
79 #define CCMAT_GG (CMAT_YG*CMAT_YG + CMAT_UG*CMAT_UG + CMAT_VG*CMAT_VG)
80 #define CCMAT_GB (CMAT_YG*CMAT_YB + CMAT_UG*CMAT_UB + CMAT_VG*CMAT_VB)
81 #define CCMAT_BR (CMAT_YB*CMAT_YR + CMAT_UB*CMAT_UR + CMAT_VB*CMAT_VR)
82 #define CCMAT_BG (CMAT_YB*CMAT_YG + CMAT_UB*CMAT_UG + CMAT_VB*CMAT_VG)
83 #define CCMAT_BB (CMAT_YB*CMAT_YB + CMAT_UB*CMAT_UB + CMAT_VB*CMAT_VB)
84 
85 /* The matrices C^* C + mu e_m^T e_m */
86 #define UR_(A) ((float)A(CCMAT_RR + MU, CCMAT_RG, CCMAT_RB, \
87  CCMAT_GR, CCMAT_GG, CCMAT_GB, \
88  CCMAT_BR, CCMAT_BG, CCMAT_BB))
89 #define UG_(A) ((float)A(CCMAT_RR, CCMAT_RG, CCMAT_RB, \
90  CCMAT_GR, CCMAT_GG + MU, CCMAT_GB, \
91  CCMAT_BR, CCMAT_BG, CCMAT_BB))
92 #define UB_(A) ((float)A(CCMAT_RR, CCMAT_RG, CCMAT_RB, \
93  CCMAT_GR, CCMAT_GG, CCMAT_GB, \
94  CCMAT_BR, CCMAT_BG, CCMAT_BB + MU))
95 
96 #define UINVR_RR (UR_(INV3X3_11))
97 #define UINVR_RG (UR_(INV3X3_12))
98 #define UINVR_RB (UR_(INV3X3_13))
99 #define UINVR_GR (UR_(INV3X3_21))
100 #define UINVR_GG (UR_(INV3X3_22))
101 #define UINVR_GB (UR_(INV3X3_23))
102 #define UINVR_BR (UR_(INV3X3_31))
103 #define UINVR_BG (UR_(INV3X3_32))
104 #define UINVR_BB (UR_(INV3X3_33))
105 
106 #define UINVG_RR (UG_(INV3X3_11))
107 #define UINVG_RG (UG_(INV3X3_12))
108 #define UINVG_RB (UG_(INV3X3_13))
109 #define UINVG_GR (UG_(INV3X3_21))
110 #define UINVG_GG (UG_(INV3X3_22))
111 #define UINVG_GB (UG_(INV3X3_23))
112 #define UINVG_BR (UG_(INV3X3_31))
113 #define UINVG_BG (UG_(INV3X3_32))
114 #define UINVG_BB (UG_(INV3X3_33))
115 
116 #define UINVB_RR (UB_(INV3X3_11))
117 #define UINVB_RG (UB_(INV3X3_12))
118 #define UINVB_RB (UB_(INV3X3_13))
119 #define UINVB_GR (UB_(INV3X3_21))
120 #define UINVB_GG (UB_(INV3X3_22))
121 #define UINVB_GB (UB_(INV3X3_23))
122 #define UINVB_BR (UB_(INV3X3_31))
123 #define UINVB_BG (UB_(INV3X3_32))
124 #define UINVB_BB (UB_(INV3X3_33))
125 
126 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
127 
128 
144 static const int NeighX[NUMNEIGH] = {1, 1, 0, -1, -1, -1, 0, 1};
146 static const int NeighY[NUMNEIGH] = {0, -1, -1, -1, 0, 1, 1, 1};
148 static const int NeighAdj[NUMNEIGH] = {4, 5, 6, 7, 0, 1, 2, 3};
150 static const float NeighWeights[NUMORIENTATIONS][NUMNEIGH] =
151  { /* 0 1 2 3 4 5 6 7 */
152  /* Horizontal orientation */
153  {1, 0, 0, 0, 1, 0, 0, 0},
154  /* pi/8 orientation */
155  {2.0f/3, 1.0f/3, 0, 0, 2.0f/3, 1.0f/3, 0, 0},
156  /* pi 2/8 orientation */
157  {0, 1, 0, 0, 0, 1, 0, 0},
158  /* pi 3/8 orientation */
159  {0, 1.0f/3, 2.0f/3, 0, 0, 1.0f/3, 2.0f/3, 0},
160  /* Vertical orientation */
161  {0, 0, 1, 0, 0, 0, 1, 0},
162  /* pi 5/8 orientation */
163  {0, 0, 2.0f/3, 1.0f/3, 0, 0, 2.0f/3, 1.0f/3},
164  /* pi 6/8 orientation */
165  {0, 0, 0, 1, 0, 0, 0, 1},
166  /* pi 7/8 orientation */
167  {2.0f/3, 0, 0, 1.0f/3, 2.0f/3, 0, 0, 1.0f/3}
168  };
169 
170 
176 static ATTRIBUTE_ALWAYSINLINE float sqr(float x)
177 {
178  return x*x;
179 }
180 
181 
187 static ATTRIBUTE_ALWAYSINLINE float GetYComponent(float R, float G, float B)
188 {
189  return ((float)CMAT_YR)*R + ((float)CMAT_YG)*G + ((float)CMAT_YB)*B;
190 }
191 
197 static ATTRIBUTE_ALWAYSINLINE float GetUComponent(float R, float G, float B)
198 {
199  return ((float)CMAT_UR)*R + ((float)CMAT_UG)*G + ((float)CMAT_UB)*B;
200 }
201 
207 static ATTRIBUTE_ALWAYSINLINE float GetVComponent(float R, float G, float B)
208 {
209  return ((float)CMAT_VR)*R + ((float)CMAT_VG)*G + ((float)CMAT_VB)*B;
210 }
211 
212 
259 void DShrink(float (*d)[NUMNEIGH][3], float (*dtilde)[NUMNEIGH][3],
260  const float *Image, float (*Weight)[NUMNEIGH], int Width, int Height,
261  float Alpha)
262 {
263  const int NumPixels = Width*Height;
264  const float *Red = Image;
265  const float *Green = Image + NumPixels;
266  const float *Blue = Image + 2*NumPixels;
267  float RedDiff, GreenDiff, BlueDiff;
268  float dmag, dnew[NUMNEIGH][3], Cu[NUMNEIGH][3];
269  int Channel, m, x, y, n, nOffset[NUMNEIGH];
270 
271  /* Precompute offsets for refering to pixel neighbors */
272  for(n = 0; n < NUMNEIGH; n++)
273  nOffset[n] = NeighX[n] + Width*NeighY[n];
274 
275  for(y = 1; y < Height - 1; y++)
276  for(x = 1; x < Width - 1; x++)
277  {
278  m = x + Width*y;
279 
280  for(n = 0; n < NUMNEIGH; n++)
281  {
282  RedDiff = Red[m] - Red[m + nOffset[n]];
283  GreenDiff = Green[m] - Green[m + nOffset[n]];
284  BlueDiff = Blue[m] - Blue[m + nOffset[n]];
285 
286  /* Convert difference from RGB to transformed colorspace */
287  Cu[n][0] = GetYComponent(RedDiff, GreenDiff, BlueDiff);
288  Cu[n][1] = GetUComponent(RedDiff, GreenDiff, BlueDiff);
289  Cu[n][2] = GetVComponent(RedDiff, GreenDiff, BlueDiff);
290  }
291 
292  /* The d-subproblem decouples over space, and decouples between
293  * the luminance component and the two chromatic components. In
294  * the following, we first solve the subproblem for the chromatic
295  * components.
296  */
297 
298  /* Compute dnew = y and dmag = ||x||_w. */
299  for(n = 0, dmag = 0; n < NUMNEIGH; n++)
300  for(Channel = 1; Channel < 3; Channel++)
301  {
302  dnew[n][Channel] = Cu[n][Channel]
303  + d[m][n][Channel] - dtilde[m][n][Channel];
304  dmag += sqr(Weight[m][n]*d[m][n][Channel]);
305  }
306 
307  /* If ||x||_w is zero, use dmag = ||y||_w instead. */
308  if(dmag == 0)
309  for(n = 0; n < NUMNEIGH; n++)
310  for(Channel = 1; Channel < 3; Channel++)
311  dmag += sqr(Weight[m][n]*dnew[n][Channel]);
312 
313  dmag = (float)sqrt(dmag);
314 
315  for(n = 0; n < NUMNEIGH; n++)
316  for(Channel = 1; Channel < 3; Channel++)
317  {
318  /* Compute new d value by the fixed point formula. */
319  dnew[n][Channel] *= dmag
320  /(Weight[m][n]*Weight[m][n]*Alpha/GAMMA1 + dmag);
321  /* Update dtilde
322  = dtilde - C(u_m - u-N) + d_m,n + Delta d_m,n
323  = dtilde - Cu + 2*dnew - d. */
324  dtilde[m][n][Channel] += 2*dnew[n][Channel]
325  - d[m][n][Channel] - Cu[n][Channel];
326  /* Update d */
327  d[m][n][Channel] = dnew[n][Channel];
328  }
329 
330  /* Now we solve the subproblem corresponding to the luminance
331  * component. The solution has the same form as for the
332  * chrominance, so the code is nearly the same.
333  */
334  for(n = 0, dmag = 0; n < NUMNEIGH; n++)
335  {
336  dnew[n][0] = Cu[n][0] + d[m][n][0] - dtilde[m][n][0];
337  dmag += sqr(Weight[m][n]*d[m][n][0]);
338  }
339 
340  if(dmag == 0)
341  for(n = 0; n < NUMNEIGH; n++)
342  dmag += sqr(Weight[m][n]*dnew[n][0]);
343 
344  dmag = (float)sqrt(dmag);
345 
346  for(n = 0; n < NUMNEIGH; n++)
347  {
348  dnew[n][0] *= dmag/(Weight[m][n]*Weight[m][n]/GAMMA1 + dmag);
349  dtilde[m][n][0] += 2*dnew[n][0] - Cu[n][0] - d[m][n][0];
350  d[m][n][0] = dnew[n][0];
351  }
352  }
353 }
354 
355 
384 float UGaussSeidel(float *Image, float *b, float (*dtilde)[NUMNEIGH][3],
385  const float *Mosaic, int Width, int Height, int RedX, int RedY)
386 {
387  const int NumPixels = Width*Height;
388  const int GreenPos = 1 - ((RedX + RedY) & 1);
389  float *Red = Image;
390  float *Green = Image + NumPixels;
391  float *Blue = Image + 2*NumPixels;
392  float DiffNorm = 0, Rhs[3], Sum[3], NewRed, NewGreen, NewBlue;
393  int Channel, m, x, y, n, NumNeigh, nOffset[NUMNEIGH];
394 
395  for(n = 0; n < NUMNEIGH; n++)
396  nOffset[n] = NeighX[n] + Width*NeighY[n];
397 
398  for(y = 0, m = 0; y < Height; y++)
399  {
400  for(x = 0; x < Width; x++, m++)
401  {
402  Rhs[0] = Rhs[1] = Rhs[2] = 0;
403  Sum[0] = Sum[1] = Sum[2] = 0;
404 
405  /* With m = (x,y) as the current pixel, the following computes
406  Sum = sum_n (dtilde_m,n - dtilde_n,m),
407  Rhs = sum_n u_n. */
408  if(0 < x && x < Width - 1 && 0 < y && y < Height - 1)
409  { /* Current pixel (x,y) is an interior pixel */
410  NumNeigh = NUMNEIGH;
411 
412  for(n = 0; n < NUMNEIGH; n++)
413  {
414  Rhs[0] += Red[m + nOffset[n]];
415  Rhs[1] += Green[m + nOffset[n]];
416  Rhs[2] += Blue[m + nOffset[n]];
417 
418  for(Channel = 0; Channel < 3; Channel++)
419  Sum[Channel] += dtilde[m][n][Channel]
420  - dtilde[m + nOffset[n]][NeighAdj[n]][Channel];
421  }
422  }
423  else /* Current pixel (x,y) is a border pixel */
424  for(n = 0, NumNeigh = 0; n < NUMNEIGH; n++)
425  if(0 <= x + NeighX[n] && x + NeighX[n] < Width
426  && 0 <= y + NeighY[n] && y + NeighY[n] < Height)
427  {
428  NumNeigh++;
429  Rhs[0] += Red[m + nOffset[n]];
430  Rhs[1] += Green[m + nOffset[n]];
431  Rhs[2] += Blue[m + nOffset[n]];
432 
433  for(Channel = 0; Channel < 3; Channel++)
434  Sum[Channel] += dtilde[m][n][Channel]
435  - dtilde[m + nOffset[n]][NeighAdj[n]][Channel];
436  }
437 
438  /* Now use Sum and Rhs computed above to obtain
439  Sum = (Sum/2 + C Rhs) / NumNeigh
440  = sum_n (2C u_n + (dtilde_m,n - dtilde_n,m)) / (2NumNeigh). */
441  Sum[0] = (Sum[0]/2 + GetYComponent(Rhs[0], Rhs[1], Rhs[2]))
442  / NumNeigh;
443  Sum[1] = (Sum[1]/2 + GetUComponent(Rhs[0], Rhs[1], Rhs[2]))
444  / NumNeigh;
445  Sum[2] = (Sum[2]/2 + GetVComponent(Rhs[0], Rhs[1], Rhs[2]))
446  / NumNeigh;
447 
448  /* Multiply by C*, the adjoint of C, so that
449  Rhs = sum_n C* (2C u_n + (dtilde_m,n - dtilde_n,m))
450  / (2NumNeigh). */
451  Rhs[0] = (float)(CMAT_YR*Sum[0] + CMAT_UR*Sum[1] + CMAT_VR*Sum[2]);
452  Rhs[1] = (float)(CMAT_YG*Sum[0] + CMAT_UG*Sum[1] + CMAT_VG*Sum[2]);
453  Rhs[2] = (float)(CMAT_YB*Sum[0] + CMAT_UB*Sum[1] + CMAT_VB*Sum[2]);
454 
455  /* The following depends on whether (x,y) is a green, red, or blue
456  * location in the Bayer CFA. We finish computing the right-hand
457  * side as
458  *
459  * Rhs += mu e_m (f_m - b_m),
460  *
461  * where mu = gamma_2 / (2 NUMNEIGH gamma_1) and e_m is (1,0,0)^T,
462  * (0,1,0)^T, or (0,0,1)^T respectively at red, green, and blue
463  * locations. We obtain the next value of u_n by multiplication
464  * with a 3x3 inverse matrix,
465  *
466  * u^next = (C* C + mu e_m e_m^T)^-1 Rhs.
467  *
468  * The Bregman auxiliary variable is then updated as
469  *
470  * b_m += u^next_m - f_m.
471  */
472  if(((x + y) & 1) == GreenPos) /* (x,y) is a green location */
473  {
474  Rhs[1] += MU*(Mosaic[m] - b[m]);
475  NewRed = UINVG_RR*Rhs[0] + UINVG_RG*Rhs[1] + UINVG_RB*Rhs[2];
476  NewGreen = UINVG_GR*Rhs[0] + UINVG_GG*Rhs[1] + UINVG_GB*Rhs[2];
477  NewBlue = UINVG_BR*Rhs[0] + UINVG_BG*Rhs[1] + UINVG_BB*Rhs[2];
478  b[m] += NewGreen - Mosaic[m];
479  }
480  else if((y & 1) == RedY) /* (x,y) is red location */
481  {
482  Rhs[0] += MU*(Mosaic[m] - b[m]);
483  NewRed = UINVR_RR*Rhs[0] + UINVR_RG*Rhs[1] + UINVR_RB*Rhs[2];
484  NewGreen = UINVR_GR*Rhs[0] + UINVR_GG*Rhs[1] + UINVR_GB*Rhs[2];
485  NewBlue = UINVR_BR*Rhs[0] + UINVR_BG*Rhs[1] + UINVR_BB*Rhs[2];
486  b[m] += NewRed - Mosaic[m];
487  }
488  else /* (x,y) is blue location */
489  {
490  Rhs[2] += MU*(Mosaic[m] - b[m]);
491  NewRed = UINVB_RR*Rhs[0] + UINVB_RG*Rhs[1] + UINVB_RB*Rhs[2];
492  NewGreen = UINVB_GR*Rhs[0] + UINVB_GG*Rhs[1] + UINVB_GB*Rhs[2];
493  NewBlue = UINVB_BR*Rhs[0] + UINVB_BG*Rhs[1] + UINVB_BB*Rhs[2];
494  b[m] += NewBlue - Mosaic[m];
495  }
496 
497  /* Computation of DiffNorm = ||u^next - u^prev|| */
498  DiffNorm += sqr(NewRed - Red[m]);
499  DiffNorm += sqr(NewGreen - Green[m]);
500  DiffNorm += sqr(NewBlue - Blue[m]);
501 
502  Red[m] = NewRed;
503  Green[m] = NewGreen;
504  Blue[m] = NewBlue;
505  }
506  }
507 
508  return (float)sqrt(DiffNorm);
509 }
510 
511 
513 static int ConstantExtension(int n, int N)
514 {
515  return (n < 0) ? 0 : ((n >= N) ? (N-1) : n);
516 }
517 
518 
545 int ConstructGraph(float (*Weight)[NUMNEIGH], const float *Mosaic,
546  int Width, int Height, int RedX, int RedY, float Epsilon, float Sigma)
547 {
548  const int NumPixels = Width*Height;
549  boundaryext Boundary = GetBoundaryExt("wsym");
550  filter SmoothFilter = {NULL, 0, 0};
551  float *ConvTemp = NULL;
552  int *Stencil = NULL;
553  int i, j, n, x, y, Success = 0;
554 
555  if(!(ConvTemp = (float *)Malloc(sizeof(float)*NumPixels))
556  || !(Stencil = (int *)Malloc(sizeof(int)*NumPixels))
557  || IsNullFilter(SmoothFilter
558  = GaussianFilter(Sigma, (int)ceil(4*Sigma))))
559  goto Catch;
560 
561  /* Estimate the contour orientations using mosaiced contour stencils */
562  FitMosaicedStencils(Stencil, Mosaic, Width, Height, RedX, RedY);
563 
564  /* Build initial graph according to the detected contours */
565  for(y = 0, i = 0; y < Height; y++)
566  for(x = 0; x < Width; x++, i++)
567  for(n = 0; n < NUMNEIGH; n++)
568  Weight[i][n] = Epsilon + NeighWeights[Stencil[i]][n];
569 
570  /* Average shared edges */
571  for(y = 0, i = 0; y < Height; y++)
572  for(x = 0; x < Width; x++, i++)
573  for(n = 0; n < 4; n++)
574  {
575  j = ConstantExtension(x + NeighX[n], Width)
576  + Width*ConstantExtension(y + NeighY[n], Height);
577  Weight[i][n] = (Weight[i][n] + Weight[j][NeighAdj[n]])/2;
578  }
579 
580  for(y = 0, i = 0; y < Height; y++)
581  for(x = 0; x < Width; x++, i++)
582  for(n = 4; n < NUMNEIGH; n++)
583  {
584  j = ConstantExtension(x + NeighX[n], Width)
585  + Width*ConstantExtension(y + NeighY[n], Height);
586  Weight[i][n] = Weight[j][NeighAdj[n]];
587  }
588 
589  /* Spatially smooth the weights with Gaussian filtering */
590  for(n = 0; n < NUMNEIGH; n++)
591  {
592  for(y = 0; y < Height; y++)
593  Conv1D(ConvTemp + Width*y, 1,
594  (float *)Weight + n + NUMNEIGH*Width*y, NUMNEIGH,
595  SmoothFilter, Boundary, Width);
596 
597  for(x = 0; x < Width; x++)
598  Conv1D((float *)Weight + n + NUMNEIGH*x, NUMNEIGH*Width,
599  ConvTemp + x, Width,
600  SmoothFilter, Boundary, Height);
601  }
602 
603  Success = 1;
604 Catch:
605  FreeFilter(SmoothFilter);
606  Free(Stencil);
607  Free(ConvTemp);
608  return Success;
609 }
610 
611 
624 void CopyCfaValues(float *Image, const float *Mosaic, int Width, int Height,
625  int RedX, int RedY)
626 {
627  const int NumPixels = Width*Height;
628  const int GreenPos = 1 - ((RedX + RedY) & 1);
629  float *Red = Image;
630  float *Green = Image + NumPixels;
631  float *Blue = Image + 2*NumPixels;
632  int x, y, m;
633 
634  for(y = 0, m = 0; y < Height; y++)
635  for(x = 0; x < Width; x++, m++)
636  if(((x + y) & 1) == GreenPos) /* Green location */
637  Green[m] = Mosaic[m];
638  else if((y & 1) == RedY) /* Red location */
639  Red[m] = Mosaic[m];
640  else /* Blue location */
641  Blue[m] = Mosaic[m];
642 }
643 
644 
670 float EvaluateCSWL1Energy(const float *Image, int Width, int Height,
671  int RedX, int RedY, float Alpha, float (*Weight)[NUMNEIGH],
672  const float *Mosaic)
673 {
674  const int NumPixels = Width*Height;
675  float *Red = NULL, *Green, *Blue;
676  float Energy = 0, EnergyL, EnergyC, Diff[3], CDiff[3];
677  int x, y, m, n, nOffset[NUMNEIGH];
678 
679  if(!(Red = (float *)Malloc(sizeof(float)*3*NumPixels)))
680  return -1;
681 
682  memcpy(Red, Image, sizeof(float)*3*NumPixels);
683  CopyCfaValues(Red, Mosaic, Width, Height, RedX, RedY);
684  Green = Red + NumPixels;
685  Blue = Red + 2*NumPixels;
686 
687  /* Precompute offsets for refering to pixel neighbors */
688  for(n = 0; n < NUMNEIGH; n++)
689  nOffset[n] = NeighX[n] + Width*NeighY[n];
690 
691  for(y = 0, m = 0; y < Height; y++)
692  for(x = 0; x < Width; x++, m++)
693  {
694  EnergyL = EnergyC = 0;
695 
696  for(n = 0; n < NUMNEIGH; n++)
697  if(0 <= x + NeighX[n] && x + NeighX[n] < Width
698  && 0 <= y + NeighY[n] && y + NeighY[n] < Height)
699  {
700  Diff[0] = Red[m] - Red[m + nOffset[n]];
701  Diff[1] = Green[m] - Green[m + nOffset[n]];
702  Diff[2] = Blue[m] - Blue[m + nOffset[n]];
703 
704  /* Convert from RGB to transformed colorspace */
705  CDiff[0] = GetYComponent(Diff[0], Diff[1], Diff[2]);
706  CDiff[1] = GetUComponent(Diff[0], Diff[1], Diff[2]);
707  CDiff[2] = GetVComponent(Diff[0], Diff[1], Diff[2]);
708 
709  /* Energy in the luminance "L" term */
710  EnergyL += Weight[m][n]*CDiff[0]*CDiff[0];
711  /* Energy in the chromatic "C" term */
712  EnergyC += Weight[m][n]*(
713  CDiff[1]*CDiff[1] + CDiff[2]*CDiff[2]);
714  }
715 
716  Energy += (float)(sqrt(EnergyL) + Alpha*sqrt(EnergyC));
717  }
718 
719  Free(Red);
720  return Energy;
721 }
722 
723 
750 int CSWL1Demosaic(float *Image, int Width, int Height,
751  int RedX, int RedY, float Alpha, float Epsilon, float Sigma,
752  float Tol, int MaxIter, int ShowEnergy)
753 {
754  const int NumPixels = Width*Height;
755  const int NumEl = 3*NumPixels;
756  float *Mosaic = NULL, (*Weight)[NUMNEIGH] = NULL, *b = NULL;
757  float (*d)[NUMNEIGH][3] = NULL, (*dtilde)[NUMNEIGH][3] = NULL;
758  double InputNorm;
759  unsigned long StartTime;
760  float DiffNorm = 0;
761  int *Stencil = NULL;
762  int Iter, Channel, i, n, Success = 0;
763 
764  /* Allocate memory */
765  if(!(Weight = (float (*)[NUMNEIGH])
766  Malloc(sizeof(float)*NUMNEIGH*NumPixels))
767  || !(d = (float (*)[NUMNEIGH][3])
768  Malloc(sizeof(float)*NUMNEIGH*NumEl))
769  || !(dtilde = (float (*)[NUMNEIGH][3])
770  Malloc(sizeof(float)*NUMNEIGH*NumEl))
771  || !(b = (float *)Malloc(sizeof(float)*NumPixels))
772  || !(Mosaic = (float *)Malloc(sizeof(float)*NumPixels)))
773  goto Catch;
774 
775  /* Start the timer */
776  StartTime = Clock();
777 
778  /* Flatten the input mosaiced image into a 2D array */
779  CfaFlatten(Mosaic, Image, Width, Height, RedX, RedY);
780 
781  /* Build the graph */
782  if(!ConstructGraph(Weight, Mosaic, Width, Height,
783  RedX, RedY, Epsilon, Sigma))
784  goto Catch;
785 
786  /* Scale Tol by the norm of the mosaiced image */
787  for(i = 0, InputNorm = 0; i < NumPixels; i++)
788  InputNorm += Mosaic[i]*Mosaic[i];
789 
790  Tol *= (float)sqrt(InputNorm);
791 
792  /* Use bilinear demosaicking as the initial solution */
793  BilinearDemosaic(Image, Mosaic, Width, Height, RedX, RedY);
794 
795  /* Initialize d, dtilde, and b to zero. Note that it is not safely
796  portable to use calloc or memset for this purpose.
797  http://c-faq.com/malloc/calloc.html */
798  for(i = 0; i < NumPixels; i++)
799  for(n = 0; n < NUMNEIGH; n++)
800  for(Channel = 0; Channel < 3; Channel++)
801  d[i][n][Channel] = 0;
802 
803  for(i = 0; i < NumPixels; i++)
804  for(n = 0; n < NUMNEIGH; n++)
805  for(Channel = 0; Channel < 3; Channel++)
806  dtilde[i][n][Channel] = 0;
807 
808  for(i = 0; i < NumPixels; i++)
809  b[i] = 0;
810 
811  /* If the ShowEnergy flag is nonzero, we display a table with the
812  * iteration count in the first column and energy in the second column.
813  * Computing the energy value is unnecessary for the optimization itself
814  * and it is somewhat expensive, so we only compute it if ShowEnergy is
815  * enabled.
816  */
817  if(ShowEnergy)
818  {
819  printf(" Iter Energy\n");
820  printf("%5d %10.1f\n", 0,
821  EvaluateCSWL1Energy(Image, Width, Height,
822  RedX, RedY, Alpha, Weight, Mosaic));
823  }
824 
825  /* Bregman iterations */
826  for(Iter = 1; Iter <= MaxIter; Iter++)
827  {
828  /* Solve the D-subproblem (updates d and dtilde) */
829  DShrink(d, dtilde, Image, Weight, Width, Height, Alpha);
830  /* Solve the U-subproblem (updates u and b) */
831  DiffNorm = UGaussSeidel(Image, b, dtilde, Mosaic,
832  Width, Height, RedX, RedY);
833 
834  if(ShowEnergy)
835  printf("%5d %10.1f\n", Iter,
836  EvaluateCSWL1Energy(Image, Width, Height,
837  RedX, RedY, Alpha, Weight, Mosaic));
838 
839  if(DiffNorm <= Tol && Iter > 2)
840  {
841  printf("Converged in %d iterations.\n", Iter);
842  break;
843  }
844  }
845 
846  if(Iter > MaxIter && !(DiffNorm <= Tol))
847  printf("Maximum number of iterations exceeded.\n");
848 
849  /* Ensure that final solution matches input data on the CFA. */
850  CopyCfaValues(Image, Mosaic, Width, Height, RedX, RedY);
851 
852  /* Print the time it took to perform the demosaicking */
853  printf("CPU Time: %.3f s\n", 0.001f*(Clock() - StartTime));
854 
855  Success = 1;
856 Catch:
857  Free(Stencil);
858  Free(b);
859  Free(Mosaic);
860  Free(dtilde);
861  Free(d);
862  Free(Weight);
863  return Success;
864 }