Linear Methods for Image Interpolation
|
00001 00021 #include <stdlib.h> 00022 #include <math.h> 00023 #include <fftw3.h> 00024 #include "adaptlob.h" 00025 #include "lprefilt.h" 00026 00027 00048 static void PrefilterScan(float *Data, int Stride, int N, float alpha, 00049 boundaryhandling Boundary) 00050 { 00051 const float Eps = 1e-4; 00052 float Sum, Weight, Last; 00053 int i, iEnd, n0; 00054 00055 n0 = (int)ceil(log(Eps)/log(fabs(alpha))); 00056 00057 if(n0 > N) 00058 n0 = N; 00059 00060 switch(Boundary) 00061 { 00062 case BOUNDARY_CONSTANT: 00063 Sum = Data[0]/(1 - alpha); 00064 break; 00065 case BOUNDARY_WSYMMETRIC: 00066 Sum = Data[0]; 00067 Weight = 1; 00068 iEnd = n0*Stride; 00069 00070 for(i = Stride; i < iEnd; i += Stride) 00071 { 00072 Weight *= alpha; 00073 Sum += Data[i]*Weight; 00074 } 00075 break; 00076 default: /* BOUNDARY_HSYMMETRIC */ 00077 Sum = Data[0]*(1 + alpha); 00078 Weight = alpha; 00079 iEnd = n0*Stride; 00080 00081 for(i = Stride; i < iEnd; i += Stride) 00082 { 00083 Weight *= alpha; 00084 Sum += Data[i]*Weight; 00085 } 00086 break; 00087 } 00088 00089 Last = Data[0] = Sum; 00090 iEnd = (N - 1)*Stride; 00091 00092 for(i = Stride; i < iEnd; i += Stride) 00093 { 00094 Data[i] += alpha*Last; 00095 Last = Data[i]; 00096 } 00097 00098 switch(Boundary) 00099 { 00100 case BOUNDARY_CONSTANT: 00101 Last = Data[iEnd] = (alpha*(-Data[iEnd] + (alpha - 1)*alpha*Last)) 00102 /((alpha - 1)*(alpha*alpha - 1)); 00103 break; 00104 case BOUNDARY_HSYMMETRIC: 00105 Data[iEnd] += alpha*Last; 00106 Last = Data[iEnd] *= alpha/(alpha - 1); 00107 break; 00108 case BOUNDARY_WSYMMETRIC: 00109 Data[iEnd] += alpha*Last; 00110 Last = Data[iEnd] = (alpha/(alpha*alpha - 1)) 00111 * ( Data[iEnd] + alpha*Data[iEnd - Stride] ); 00112 break; 00113 } 00114 00115 for(i = iEnd - Stride; i >= 0; i -= Stride) 00116 { 00117 Data[i] = alpha*(Last - Data[i]); 00118 Last = Data[i]; 00119 } 00120 } 00121 00122 00132 void PrefilterImage(float *Data, int Width, int Height, int NumChannels, 00133 const float *alpha, int NumFilterPairs, float ConstantFactor, 00134 boundaryhandling Boundary) 00135 { 00136 const int NumPixels = Width*Height; 00137 int k, x, y, Channel; 00138 00139 00140 /* Square the ConstantFactor for two spatial dimensions */ 00141 ConstantFactor = ConstantFactor*ConstantFactor; 00142 00143 for(Channel = 0; Channel < NumChannels; Channel++) 00144 { 00145 for(x = 0; x < Width; x++) 00146 for(k = 0; k < NumFilterPairs; k++) 00147 PrefilterScan(Data + x, Width, Height, alpha[k], Boundary); 00148 00149 for(y = 0; y < Height; y++) 00150 for(k = 0; k < NumFilterPairs; k++) 00151 PrefilterScan(Data + Width*y, 1, Width, alpha[k], Boundary); 00152 00153 for(k = 0; k < NumPixels; k++) 00154 Data[k] *= ConstantFactor; 00155 00156 Data += NumPixels; 00157 } 00158 } 00159 00160 00161 typedef struct { 00162 float (*Kernel)(float); 00163 float KernelRadius; 00164 float (*Psf)(float, const void*); 00165 const void *PsfParams; 00166 float x; 00167 } convolutionparams; 00168 00169 00170 static float ConvIntegrand(float t, const void *Params) 00171 { 00172 float (*Kernel)(float) = ((convolutionparams*)Params)->Kernel; 00173 float (*Psf)(float, const void*) = ((convolutionparams*)Params)->Psf; 00174 const void *PsfParams = ((convolutionparams*)Params)->PsfParams; 00175 float x = ((convolutionparams*)Params)->x; 00176 00177 return Kernel(t) * Psf(x - t, PsfParams); 00178 } 00179 00180 00181 static float ConvIntegrandNormalized(float t, const void *Params) 00182 { 00183 float (*Kernel)(float) = ((convolutionparams*)Params)->Kernel; 00184 const int R = 2*ceil(((convolutionparams*)Params)->KernelRadius); 00185 float (*Psf)(float, const void*) = ((convolutionparams*)Params)->Psf; 00186 const void *PsfParams = ((convolutionparams*)Params)->PsfParams; 00187 float Sum, x = ((convolutionparams*)Params)->x; 00188 int r; 00189 00190 for(r = -R, Sum = 0; r <= R; r++) 00191 Sum += Kernel(t - r); 00192 00193 return (Kernel(t)/Sum) * Psf(x - t, PsfParams); 00194 } 00195 00196 00214 void PsfConvCoeff(float *Coeff, int NumCoeffs, 00215 float (*Psf)(float, const void*), const void *PsfParams, 00216 float (*Kernel)(float), float KernelRadius, int KernelNormalize) 00217 { 00218 float (*ConvFun)(float, const void*) = ConvIntegrand; 00219 convolutionparams ConvParams; 00220 int m; 00221 00222 ConvParams.Kernel = Kernel; 00223 ConvParams.KernelRadius = KernelRadius; 00224 ConvParams.Psf = Psf; 00225 ConvParams.PsfParams = PsfParams; 00226 00227 if(KernelNormalize) 00228 ConvFun = ConvIntegrandNormalized; 00229 00230 for(m = 0; m < NumCoeffs; m++) 00231 { 00232 ConvParams.x = m; 00233 Coeff[m] = AdaptLob(ConvFun, -KernelRadius, KernelRadius, 00234 1e-7f, (const void *)&ConvParams); 00235 } 00236 } 00237 00238 00266 static int PsfPreFilterScan(float *Data, int Stride, int ScanSize, 00267 int ScanStride, int NumScans, int ChannelStride, int NumChannels, 00268 const float *Coeff, int NumCoeffs, boundaryhandling Boundary) 00269 { 00270 const int PadCoeff = ScanSize + ((Boundary == BOUNDARY_HSYMMETRIC) ? 1:0); 00271 float *Buf = NULL, *CoeffDct = NULL; 00272 fftwf_plan Plan = 0; 00273 fftwf_iodim Dims[1], HowManyDims[2]; 00274 fftw_r2r_kind Kind[1]; 00275 int i, Scan, Channel, Success = 0; 00276 00277 00278 if((Boundary != BOUNDARY_HSYMMETRIC && Boundary != BOUNDARY_WSYMMETRIC) 00279 || !(Buf = (float *)fftwf_malloc(sizeof(float)*ScanSize*NumScans*NumChannels)) 00280 || !(CoeffDct = (float *)fftwf_malloc(sizeof(float)*PadCoeff))) 00281 goto Catch; 00282 00283 for(i = 0; i < NumCoeffs && i < PadCoeff; i++) 00284 Buf[i] = Coeff[i]; 00285 for(; i < PadCoeff; i++) 00286 Buf[i] = 0; 00287 00288 /* Perform DCT-I */ 00289 if(!(Plan = fftwf_plan_r2r_1d(PadCoeff, Buf, CoeffDct, 00290 FFTW_REDFT00, FFTW_ESTIMATE | FFTW_DESTROY_INPUT))) 00291 goto Catch; 00292 00293 fftwf_execute(Plan); 00294 fftwf_destroy_plan(Plan); 00295 00296 /* Incorporate the normalization scale factor into the coefficients */ 00297 for(i = 0; i < ScanSize; i++) 00298 CoeffDct[i] *= 2*(PadCoeff - 1); 00299 00300 /* Forward transform of the image data */ 00301 Dims[0].n = ScanSize; 00302 Dims[0].is = Stride; 00303 Dims[0].os = 1; 00304 HowManyDims[0].n = NumChannels; 00305 HowManyDims[0].is = ChannelStride; 00306 HowManyDims[0].os = ScanSize*NumScans; 00307 HowManyDims[1].n = NumScans; 00308 HowManyDims[1].is = ScanStride; 00309 HowManyDims[1].os = ScanSize; 00310 00311 /* Use DCT-II for half-sample symmetric boundaries, 00312 DCT-I for whole-sample symmetric. */ 00313 Kind[0] = (Boundary == BOUNDARY_HSYMMETRIC) ? FFTW_REDFT10 : FFTW_REDFT00; 00314 00315 if(!(Plan = fftwf_plan_guru_r2r(1, Dims, 2, HowManyDims, Data, 00316 Buf, Kind, FFTW_ESTIMATE | FFTW_DESTROY_INPUT))) 00317 goto Catch; 00318 00319 fftwf_execute(Plan); 00320 fftwf_destroy_plan(Plan); 00321 00322 /* Divide */ 00323 for(Channel = 0; Channel < NumChannels; Channel++) 00324 { 00325 for(Scan = 0; Scan < NumScans; Scan++) 00326 { 00327 for(i = 0; i < ScanSize; i++) 00328 Buf[i + ScanSize*(Scan + NumScans*Channel)] /= CoeffDct[i]; 00329 } 00330 } 00331 00332 /* Perform inverse transform */ 00333 Dims[0].n = ScanSize; 00334 Dims[0].is = 1; 00335 Dims[0].os = Stride; 00336 HowManyDims[0].n = NumChannels; 00337 HowManyDims[0].is = ScanSize*NumScans; 00338 HowManyDims[0].os = ChannelStride; 00339 HowManyDims[1].n = NumScans; 00340 HowManyDims[1].is = ScanSize; 00341 HowManyDims[1].os = ScanStride; 00342 00343 /* Use DCT-III (inverse of DCT-II) for half-sample symmetric boundaries, 00344 DCT-I (inverse of DCT-I) for whole-sample symmetric. */ 00345 Kind[0] = (Boundary == BOUNDARY_HSYMMETRIC) ? FFTW_REDFT01 : FFTW_REDFT00; 00346 00347 if(!(Plan = fftwf_plan_guru_r2r(1, Dims, 2, HowManyDims, Buf, 00348 Data, Kind, FFTW_ESTIMATE | FFTW_DESTROY_INPUT))) 00349 goto Catch; 00350 00351 fftwf_execute(Plan); 00352 fftwf_destroy_plan(Plan); 00353 Success = 1; 00354 Catch: 00355 if(CoeffDct) 00356 fftwf_free(CoeffDct); 00357 if(Buf) 00358 fftwf_free(Buf); 00359 fftwf_cleanup(); 00360 return Success; 00361 } 00362 00363 00380 int PsfPreFilter(float *Data, int Width, int Height, int NumChannels, 00381 const float *Coeff, int NumCoeffs, boundaryhandling Boundary) 00382 { 00383 if(!Data || !Coeff) 00384 return 0; 00385 00386 if(!PsfPreFilterScan(Data, Width, Height, 1, Width, Width*Height, 00387 NumChannels, Coeff, NumCoeffs, Boundary)) 00388 return 0; 00389 00390 if(!PsfPreFilterScan(Data, 1, Width, Width, Height, Width*Height, 00391 NumChannels, Coeff, NumCoeffs, Boundary)) 00392 return 0; 00393 00394 return 1; 00395 }