File Coverage

lib/PDL/Image2D/resample.c
Criterion Covered Total %
statement 74 124 59.6
branch 27 64 42.1
condition n/a
subroutine n/a
pod n/a
total 101 188 53.7


line stmt bran cond sub pod time code
1             /*
2             * resample.c
3             * - a hacked version of
4             * ipow.c, poly2d.c, and resampling.c
5             * from version 3.6-0 of the Eclipse library (ESO)
6             * by Nicolas Devillard
7             *
8             * see http://www.eso.org/eclipse for further details
9             */
10              
11             #include
12             #include "resample.h"
13              
14             /*-------------------------------------------------------------------------*/
15             /**
16             @name ipow
17             @memo Same as pow(x,y) but for integer values of y only (faster).
18             @param x A double number.
19             @param p An integer power.
20             @return x to the power p.
21             @doc
22              
23             This is much faster than the math function due to the integer. Some
24             compilers make this optimization already, some do not.
25              
26             p can be positive, negative or null.
27             */
28             /*--------------------------------------------------------------------------*/
29              
30 290000           long double ipow(long double x, int p)
31             {
32             long double r, recip ;
33              
34             /* Get rid of trivial cases */
35 290000           switch (p) {
36 90000           case 0:
37 90000           return 1.00 ;
38              
39 90000           case 1:
40 90000           return x ;
41              
42 70000           case 2:
43 70000           return x*x ;
44              
45 40000           case 3:
46 40000           return x*x*x ;
47              
48 0           case -1:
49 0           return 1.00 / x ;
50              
51 0           case -2:
52 0           return (1.00 / x) * (1.00 / x) ;
53             }
54 0 0         if (p>0) {
55 0           r = x ;
56 0 0         while (--p) r *= x ;
57             } else {
58 0           r = recip = 1.00 / x ;
59 0 0         while (++p) r *= recip ;
60             }
61 0           return r;
62             }
63              
64              
65             /*
66             * compute the value of a 2D polynomial at a point
67             * - it assumes that ncoeff is a small number, so there's
68             * little point in pre-calculating ipow(u,i)
69             */
70              
71             long double
72 30000           poly2d_compute( int ncoeff, long double *c, long double u, long double *vpow ) {
73             long double out;
74             int i, j, k;
75              
76 30000           out = 0.00;
77 30000           k = 0;
78 120000 100         for( j = 0; j < ncoeff; j++ ) {
79 380000 100         for( i = 0; i < ncoeff; i++ ) {
80 290000           out += c[k] * ipow( u, i ) * vpow[j];
81 290000           k++;
82             }
83             }
84 30000           return out;
85             }
86              
87             /*-------------------------------------------------------------------------*/
88             /**
89             @name sinc
90             @memo Cardinal sine.
91             @param x double value.
92             @return 1 double.
93             @doc
94              
95             Compute the value of the function sinc(x)=sin(pi*x)/(pi*x) at the
96             requested x.
97             */
98             /*--------------------------------------------------------------------------*/
99              
100             double
101 0           sinc(double x)
102             {
103 0 0         if (fabs(x)<1e-4)
104 0           return (double)1.00 ;
105             else
106 0           return ((sin(x * (double)PI_NUMB)) / (x * (double)PI_NUMB)) ;
107             } /* sinc() */
108              
109             /**
110             @name reverse_tanh_kernel
111             @memo Bring a hyperbolic tangent kernel from Fourier to normal space.
112             @param data Kernel samples in Fourier space.
113             @param nn Number of samples in the input kernel.
114             @return void
115             @doc
116              
117             Bring back a hyperbolic tangent kernel from Fourier to normal space. Do
118             not try to understand the implementation and DO NOT MODIFY THIS FUNCTION.
119             */
120             /*--------------------------------------------------------------------------*/
121              
122             #define KERNEL_SW(a,b) tempr=(a);(a)=(b);(b)=tempr
123 6           static void reverse_tanh_kernel(long double * data, int nn)
124             {
125             unsigned long n,
126             mmax,
127             m,
128             i, j,
129             istep ;
130             long double wtemp,
131             wr,
132             wpr,
133             wpi,
134             wi,
135             theta;
136             long double tempr,
137             tempi;
138              
139 6           n = (unsigned long)nn << 1;
140 6           j = 1;
141 196614 100         for (i=1 ; i
142 196608 100         if (j > i) {
143 97536           KERNEL_SW(data[j-1],data[i-1]);
144 97536           KERNEL_SW(data[j],data[i]);
145             }
146 196608           m = n >> 1;
147 393210 100         while (m>=2 && j>m) {
    100          
148 196602           j -= m;
149 196602           m >>= 1;
150             }
151 196608           j += m;
152             }
153 6           mmax = 2;
154 96 100         while (n > mmax) {
155 90           istep = mmax << 1;
156 90           theta = 2 * M_PI / mmax;
157 90           wtemp = sin(0.5 * theta);
158 90           wpr = -2.0 * wtemp * wtemp;
159 90           wpi = sin(theta);
160 90           wr = 1.0;
161 90           wi = 0.0;
162 196692 100         for (m=1 ; m
163 1671162 100         for (i=m ; i<=n ; i+=istep) {
164 1474560           j = i + mmax;
165 1474560           tempr = wr * data[j-1] - wi * data[j];
166 1474560           tempi = wr * data[j] + wi * data[j-1];
167 1474560           data[j-1] = data[i-1] - tempr;
168 1474560           data[j] = data[i] - tempi;
169 1474560           data[i-1] += tempr;
170 1474560           data[i] += tempi;
171             }
172 196602           wr = (wtemp = wr) * wpr - wi * wpi + wr;
173 196602           wi = wi * wpr + wtemp * wpi + wi;
174             }
175 90           mmax = istep;
176             }
177 6           } /* reverse_tanh_kernel() */
178             #undef KERNEL_SW
179              
180             /*-------------------------------------------------------------------------*/
181             /**
182             @name generate_tanh_kernel
183             @memo Generate a hyperbolic tangent kernel.
184             @param steep Steepness of the hyperbolic tangent parts.
185             @param samples Number of samples
186             @param kernel Block of (samples) * long double
187             @doc
188              
189             The following function builds up a good approximation of a box filter. It
190             is built from a product of hyperbolic tangents. It has the following
191             properties:
192              
193             \begin{itemize}
194             \item It converges very quickly towards +/- 1.
195             \item The converging transition is very sharp.
196             \item It is infinitely differentiable everywhere (i.e. smooth).
197             \item The transition sharpness is scalable.
198             \end{itemize}
199             */
200             /*--------------------------------------------------------------------------*/
201              
202             #define hk_gen(x,s) (((tanh(s*(x+0.5))+1)/2)*((tanh(s*(-x+0.5))+1)/2))
203              
204 6           void generate_tanh_kernel(long double steep, int samples, long double *kernel)
205             {
206             long double * x ;
207             long double width ;
208             long double inv_np ;
209             long double ind ;
210             int i ;
211             int np ;
212              
213 6           width = (long double)TABSPERPIX / 2.0 ;
214 6           np = 32768 ; /* Hardcoded: should never be changed */
215 6           inv_np = 1.00 / (long double)np ;
216              
217             /*
218             * Generate the kernel expression in Fourier space
219             * with a correct frequency ordering to allow standard FT
220             */
221 6           x = (long double *) malloc((2*np+1)*sizeof(long double)) ;
222 98310 100         for (i=0 ; i
223 98304           ind = (long double)i * 2.0 * width * inv_np ;
224 98304           x[2*i] = hk_gen(ind, steep) ;
225 98304           x[2*i+1] = 0.00 ;
226             }
227 98310 100         for (i=np/2 ; i
228 98304           ind = (long double)(i-np) * 2.0 * width * inv_np ;
229 98304           x[2*i] = hk_gen(ind, steep) ;
230 98304           x[2*i+1] = 0.00 ;
231             }
232              
233             /*
234             * Reverse Fourier to come back to image space
235             */
236 6           reverse_tanh_kernel(x, np) ;
237              
238             /*
239             * fill in passed-in array
240             */
241 12012 100         for (i=0 ; i
242 12006           kernel[i] = 2.0 * width * x[2*i] * inv_np ;
243             }
244 6           free(x) ;
245 6           } /* generate_tanh_kernel() */
246              
247              
248             /*-------------------------------------------------------------------------*/
249             /**
250             @name generate_interpolation_kernel
251             @memo Generate an interpolation kernel to use in this module.
252             @param kernel_type Type of interpolation kernel.
253             @param samples Number of samples
254             @param kernel Block of (samples) * long double
255             @return true on success
256             @doc
257              
258             Provide the name of the kernel you want to generate. Supported kernel
259             types are:
260              
261             \begin{tabular}{ll}
262             NULL & default kernel, currently "tanh" \\
263             "default" & default kernel, currently "tanh" \\
264             "tanh" & Hyperbolic tangent \\
265             "sinc2" & Square sinc \\
266             "lanczos" & Lanczos2 kernel \\
267             "hamming" & Hamming kernel \\
268             "hann" & Hann kernel
269             \end{tabular}
270              
271             The filled-in array of long doubles is ready to use in the various re-sampling
272             functions in this module.
273             */
274             /*--------------------------------------------------------------------------*/
275              
276             char
277 6           generate_interpolation_kernel(char *kernel_type, int samples, long double *tab)
278             {
279             int i ;
280             long double x ;
281             long double alpha ;
282             long double inv_norm ;
283 6 50         if (kernel_type==NULL || !strcmp(kernel_type, "default") || !strcmp(kernel_type, "tanh")) {
    50          
    50          
284 6           generate_tanh_kernel(TANH_STEEPNESS, samples, tab) ;
285 0 0         } else if (!strcmp(kernel_type, "sinc")) {
286 0           tab[0] = 1.0 ;
287 0           tab[samples-1] = 0.0 ;
288 0 0         for (i=1 ; i
289 0           x = (long double)KERNEL_WIDTH * (long double)i/(long double)(samples-1) ;
290 0           tab[i] = sinc(x) ;
291             }
292 0 0         } else if (!strcmp(kernel_type, "sinc2")) {
293 0           tab[0] = 1.0 ;
294 0           tab[samples-1] = 0.0 ;
295 0 0         for (i=1 ; i
296 0           x = 2.0 * (long double)i/(long double)(samples-1) ;
297 0           tab[i] = sinc(x) ;
298 0           tab[i] *= tab[i] ;
299             }
300 0 0         } else if (!strcmp(kernel_type, "lanczos")) {
301 0 0         for (i=0 ; i
302 0           x = (long double)KERNEL_WIDTH * (long double)i/(long double)(samples-1) ;
303 0 0         if (fabsl(x)<2) {
304 0           tab[i] = sinc(x) * sinc(x/2) ;
305             } else {
306 0           tab[i] = 0.00 ;
307             }
308             }
309 0 0         } else if (!strcmp(kernel_type, "hamming")) {
310 0           alpha = 0.54 ;
311 0           inv_norm = 1.00 / (long double)(samples - 1) ;
312 0 0         for (i=0 ; i
313 0           x = (long double)i ;
314 0 0         if (i<(samples-1)/2) {
315 0           tab[i] = alpha + (1-alpha) * cos(2.0*PI_NUMB*x*inv_norm) ;
316             } else {
317 0           tab[i] = 0.0 ;
318             }
319             }
320 0 0         } else if (!strcmp(kernel_type, "hann")) {
321 0           alpha = 0.50 ;
322 0           inv_norm = 1.00 / (long double)(samples - 1) ;
323 0 0         for (i=0 ; i
324 0           x = (long double)i ;
325 0 0         if (i<(samples-1)/2) {
326 0           tab[i] = alpha + (1-alpha) * cos(2.0*PI_NUMB*x*inv_norm) ;
327             } else {
328 0           tab[i] = 0.0 ;
329             }
330             }
331             } else {
332             /**
333             ** trapped at perl level, so should never reach here
334             e_error("unrecognized kernel type [%s]: aborting generation",
335             kernel_type) ;
336             **/
337 0           return 0;
338             }
339 6           return 1;
340             } /* generate_interpolation_kernel() */