Total Variation Deconvolution using Split Bregman
kernels.c
Go to the documentation of this file.
1 
16 #include <stdio.h>
17 #include <string.h>
18 #include <math.h>
19 #include "kernels.h"
20 
21 #ifndef M_SQRT1_2
22 
23 #define M_SQRT1_2 0.70710678118654752440084436210484904
24 #endif
25 
26 #ifndef M_PI
27 
28 #define M_PI 3.14159265358979323846264338327950288
29 #endif
30 
31 
32 static int KernelRescale(image *Kernel)
33 {
34  const int NumEl = Kernel->Width * Kernel->Height;
35  num *Data = Kernel->Data;
36  num Sum = 0;
37  int n;
38 
39  for(n = 0; n < NumEl; n++)
40  Sum += Data[n];
41 
42  if(Sum == 0)
43  {
44  fprintf(stderr, "Kernel must have nonzero sum.\n");
45  return 0;
46  }
47 
48  for(n = 0; n < NumEl; n++)
49  Data[n] /= Sum;
50 
51  return 1;
52 }
53 
54 
55 static int GaussianKernel(image *Kernel, num Sigma)
56 {
57  const int R = (int)ceil(4*Sigma);
58  const int W = 2*R + 1;
59  const double ExpDenom = 2.0*(double)Sigma*(double)Sigma;
60  num *Data;
61  double Sum;
62  int x, y;
63 
64 
65  if(!Kernel || Sigma < 0.0 || !(AllocImageObj(Kernel, W, W, 1)))
66  return 0;
67 
68  Data = Kernel->Data;
69 
70  if(Sigma == 0.0)
71  Data[0] = 1;
72  else
73  {
74  for(y = -R, Sum = 0; y <= R; y++)
75  for(x = -R; x <= R; x++)
76  {
77  Data[(R + x) + W*(R + y)] = (num)exp(-(x*x + y*y)/ExpDenom);
78  Sum += Data[(R + x) + W*(R + y)];
79  }
80 
81  for(y = -R; y <= R; y++)
82  for(x = -R; x <= R; x++)
83  Data[(R + x) + W*(R + y)] =
84  (num)(Data[(R + x) + W*(R + y)]/Sum);
85  }
86 
87  return 1;
88 }
89 
90 
91 static int DiskKernel(image *Kernel, num Radius)
92 {
93  const int R = (int)ceil(Radius - 0.5);
94  const int W = 2*R + 1;
95  const int Res = 8;
96  const double RadiusSqr = (double)Radius*(double)Radius;
97  const double RadiusInnerSqr =
98  ((double)Radius - M_SQRT1_2)*((double)Radius - M_SQRT1_2);
99  const double RadiusOuterSqr =
100  ((double)Radius + M_SQRT1_2)*((double)Radius + M_SQRT1_2);
101  num *Data;
102  double Sum, xl, yl, Start = -0.5 + 0.5/Res, Step = 1.0/Res;
103  int c, x, y, m, n;
104 
105 
106  if(!Kernel || Radius < 0.0 || !(AllocImageObj(Kernel, W, W, 1)))
107  return 0;
108 
109  Data = Kernel->Data;
110 
111  if(Radius <= 0.5)
112  Data[0] = 1;
113  else
114  {
115  for(y = -R, Sum = 0; y <= R; y++)
116  for(x = -R; x <= R; x++)
117  {
118  if(x*x + y*y <= RadiusInnerSqr)
119  c = Res*Res;
120  else if(x*x + y*y > RadiusOuterSqr)
121  c = 0;
122  else
123  for(n = 0, yl = y + Start, c = 0; n < Res; n++, yl += Step)
124  for(m = 0, xl = x + Start; m < Res; m++, xl += Step)
125  if(xl*xl + yl*yl <= RadiusSqr)
126  c++;
127 
128  Data[(R + x) + W*(R + y)] = (num)c;
129  Sum += c;
130  }
131 
132  for(y = -R; y <= R; y++)
133  for(x = -R; x <= R; x++)
134  Data[(R + x) + W*(R + y)] =
135  (num)(Data[(R + x) + W*(R + y)]/Sum);
136  }
137 
138  return 1;
139 }
140 
141 
142 static int MakeNamedKernel(image *Kernel, const char *String)
143 {
144  const char *ColonPtr;
145  num KernelParam;
146  int Length;
147  char KernelName[32];
148 
149  if(!Kernel || !(ColonPtr = strchr(String, ':'))
150  || (Length = (int)(ColonPtr - String)) > 9)
151  return 0;
152 
153  strncpy(KernelName, String, Length);
154  KernelName[Length] = '\0';
155  KernelParam = (num)atof(ColonPtr + 1);
156 
157  if(!strcmp(KernelName, "Gaussian") || !strcmp(KernelName, "gaussian"))
158  return GaussianKernel(Kernel, KernelParam);
159  else if(!strcmp(KernelName, "Disk") || !strcmp(KernelName, "disk"))
160  return DiskKernel(Kernel, KernelParam);
161  else
162  return 0;
163 }
164 
165 
175 int ReadKernel(image *Kernel, const char *String)
176 {
177  if(Kernel->Data)
178  {
179  FreeImageObj(*Kernel);
180  *Kernel = NullImage;
181  }
182 
183  if(MakeNamedKernel(Kernel, String)
184  || ReadMatrixFromFile(Kernel, String, KernelRescale))
185  return 1;
186  else
187  return 0;
188 }