34 #define CLAMP(X,A,B) (((X) < (A)) ? (A) : (((X) > (B)) ? (B) : (X)))
43 static int ConstExtension(
int N,
int i)
60 static int HSymExtension(
int N,
int i)
80 static int WSymExtension(
int N,
int i)
96 {ConstExtension, HSymExtension, WSymExtension};
146 int LinInterp2d(
float *Dest,
const float *Src,
int SrcWidth,
int SrcHeight,
147 float *X,
float *Y,
int NumSamples,
148 float (*Kernel)(
float),
float KernelRadius,
int KernelNormalize,
152 const int KernelWidth = (int)ceil(2*KernelRadius);
153 float *KernelXBuf = NULL, *KernelYBuf = NULL;
154 float Weight, Sum, DenomSum;
155 int IndexX0, IndexY0, IndexX, IndexY, SrcRowOffset;
156 int k, m, n, Success = 0;
158 if(!Dest || !Src || SrcWidth <= 0 || SrcHeight <= 0 || !X || !Y
159 || NumSamples < 0 || !Kernel || KernelRadius < 0
160 || !(KernelXBuf = (
float *)
Malloc(
sizeof(
float)*(KernelWidth)))
161 || !(KernelYBuf = (
float *)
Malloc(
sizeof(
float)*(KernelWidth))))
165 for(k = 0; k < NumSamples; k++)
167 IndexX0 = (int)ceil(X[k] - KernelRadius);
168 IndexY0 = (int)ceil(Y[k] - KernelRadius);
172 for(m = 0; m < KernelWidth; m++)
173 KernelXBuf[m] = Kernel(X[k] - (IndexX0 + m));
175 for(n = 0; n < KernelWidth; n++)
176 KernelYBuf[n] = Kernel(Y[k] - (IndexY0 + n));
179 for(n = 0; n < KernelWidth; n++)
181 IndexY = Extension(SrcHeight, IndexY0 + n);
182 SrcRowOffset = SrcWidth*IndexY;
184 for(m = 0; m < KernelWidth; m++)
186 IndexX = Extension(SrcWidth, IndexX0 + m);
187 Sum += Src[IndexX + SrcRowOffset]
188 * KernelXBuf[m] * KernelYBuf[n];
195 for(k = 0; k < NumSamples; k++)
197 IndexX0 = (int)ceil(X[k] - KernelRadius);
198 IndexY0 = (int)ceil(Y[k] - KernelRadius);
199 Sum = DenomSum = 0.0f;
202 for(m = 0; m < KernelWidth; m++)
203 KernelXBuf[m] = Kernel(X[k] - (IndexX0 + m));
205 for(n = 0; n < KernelWidth; n++)
206 KernelYBuf[n] = Kernel(Y[k] - (IndexY0 + n));
209 for(n = 0; n < KernelWidth; n++)
211 IndexY = Extension(SrcHeight, IndexY0 + n);
212 SrcRowOffset = SrcWidth*IndexY;
214 for(m = 0; m < KernelWidth; m++)
216 IndexX = Extension(SrcWidth, IndexX0 + m);
217 Weight = KernelXBuf[m] * KernelYBuf[n];
218 Sum += Src[IndexX + SrcRowOffset] * Weight;
223 Dest[k] = Sum / DenomSum;
253 int *GridHeight,
int SrcWidth,
int SrcHeight,
float Scale,
float Theta)
255 const int ScaleWidth = floor(Scale*SrcWidth + 0.5f);
256 const int ScaleHeight = floor(Scale*SrcHeight + 0.5f);
257 const float x0 = (float)ScaleWidth/2.0f;
258 const float y0 = (float)ScaleHeight/2.0f;
259 const float CosTheta = (float)cos(Theta);
260 const float SinTheta = (float)sin(Theta);
261 float CurX, CurY, XStart, YStart, *XPtr, *YPtr;
265 if(!X || !Y || !GridWidth || !GridHeight
266 || SrcWidth <= 0 || SrcHeight <= 0 || Scale <= 0)
272 XStart = -fabs(CosTheta)*x0 - fabs(SinTheta)*y0;
273 YStart = -fabs(SinTheta)*x0 - fabs(CosTheta)*y0;
274 *GridWidth = floor(ScaleWidth*fabs(CosTheta)
275 + ScaleHeight*fabs(SinTheta) + 0.5f);
276 *GridHeight = floor(ScaleWidth*fabs(SinTheta)
277 + ScaleHeight*fabs(CosTheta) + 0.5f);
279 if(!(*X = (
float *)
Malloc(
sizeof(
float)*(*GridWidth)*(*GridHeight)))
280 || !(*Y = (
float *)
Malloc(
sizeof(
float)*(*GridWidth)*(*GridHeight))))
282 *GridWidth = *GridHeight = 0;
292 for(n = 0; n < *GridHeight; n++)
293 for(m = 0; m < *GridWidth; m++)
297 *(XPtr++) = (x0 + CosTheta*CurX - SinTheta*CurY) / Scale;
298 *(YPtr++) = (y0 + SinTheta*CurX + CosTheta*CurY) / Scale;
313 static void ScaleScan(
float *Dest,
int DestStride,
int DestWidth,
314 const float *Src,
int SrcStride,
321 for(x = 0; x < DestWidth; x++)
323 SrcIndex = Filter.
Pos[x] * SrcStride;
326 for(k = 0; k < Filter.
Width; k++, SrcIndex += SrcStride)
327 Sum += Filter.
Coeff[k] * Src[SrcIndex];
356 int DestWidth,
float XStart,
float XStep,
int SrcWidth,
357 float (*Kernel)(
float),
float KernelRadius,
int KernelNormalize,
361 const int KernelWidth = (int)ceil(2*KernelRadius);
362 const int FilterWidth = (SrcWidth < KernelWidth) ? SrcWidth : KernelWidth;
363 float *FilterCoeff = NULL;
364 int16_t *FilterPos = NULL;
366 int n, DestX, Pos, MaxPos;
369 if(!(FilterCoeff = (
float *)
Malloc(
sizeof(
float)*FilterWidth*DestWidth))
370 || !(FilterPos = (int16_t *)
Malloc(
sizeof(int16_t)*DestWidth)))
373 Filter->
Coeff = NULL;
379 Filter->
Coeff = FilterCoeff;
380 Filter->
Pos = FilterPos;
381 Filter->
Width = FilterWidth;
382 MaxPos = SrcWidth - FilterWidth;
384 for(DestX = 0; DestX < DestWidth; DestX++)
386 SrcX = XStart + XStep*DestX;
387 Pos = (int)ceil(SrcX - KernelRadius);
389 if(Pos < 0 || MaxPos < Pos)
391 FilterPos[DestX] =
CLAMP(Pos, 0, MaxPos);
393 for(n = 0; n < FilterWidth; n++)
396 for(n = 0; n < KernelWidth; n++)
397 FilterCoeff[Extension(SrcWidth, Pos + n) - FilterPos[DestX]]
398 += Kernel(SrcX - (Pos + n));
402 FilterPos[DestX] = Pos;
404 for(n = 0; n < FilterWidth; n++)
405 FilterCoeff[n] = Kernel(SrcX - (Pos + n));
412 for(n = 0; n < FilterWidth; n++)
413 Sum += FilterCoeff[n];
415 for(n = 0; n < FilterWidth; n++)
416 FilterCoeff[n] /= Sum;
419 FilterCoeff += FilterWidth;
463 int LinScale2d(
float *Dest,
int DestWidth,
float XStart,
float XStep,
464 int DestHeight,
float YStart,
float YStep,
465 const float *Src,
int SrcWidth,
int SrcHeight,
int NumChannels,
466 float (*Kernel)(
float),
float KernelRadius,
int KernelNormalize,
469 const int SrcNumPixels = SrcWidth*SrcHeight;
470 const int DestNumPixels = DestWidth*DestHeight;
473 int x, y, Channel, Success = 0;
476 if(!Dest || DestWidth <= 0 || DestHeight <= 0 || !Src
477 || SrcWidth <= 0 || SrcHeight <= 0 || NumChannels <= 0
478 || !Kernel || KernelRadius < 0)
480 if(!(Buf = (
float *)
Malloc(
sizeof(
float)*SrcWidth*DestHeight))
481 || !MakeScaleScanFilter(&HFilter, DestWidth, XStart, XStep,
482 SrcWidth, Kernel, KernelRadius, KernelNormalize, Boundary)
483 || !MakeScaleScanFilter(&VFilter, DestHeight, YStart, YStep,
484 SrcHeight, Kernel, KernelRadius, KernelNormalize, Boundary))
487 for(Channel = 0; Channel < NumChannels; Channel++)
489 for(x = 0; x < SrcWidth; x++)
490 ScaleScan(Buf + x, SrcWidth, DestHeight,
491 Src + x, SrcWidth, VFilter);
493 for(y = 0; y < DestHeight; y++)
494 ScaleScan(Dest + y*DestWidth, 1, DestWidth,
495 Buf + y*SrcWidth, 1, HFilter);
498 Dest += DestNumPixels;
512 static int FourierScaleScan(
float *Dest,
513 int DestStride,
int DestScanStride,
int DestChannelStride,
int DestScanSize,
515 int SrcStride,
int SrcScanStride,
int SrcChannelStride,
int SrcScanSize,
516 int NumScans,
int NumChannels,
float XStart,
double PsfSigma,
519 const int SrcPadScanSize = 2*(SrcScanSize
523 : (2*DestScanSize - floor((2.0f*DestScanSize)/SrcScanSize + 0.5f));
524 const int ReflectOffset = SrcPadScanSize
526 const int SrcDftSize = SrcPadScanSize/2 + 1;
527 const int DestDftSize = DestPadScanSize/2 + 1;
528 const int BufSpatialNumEl = DestPadScanSize*NumScans*NumChannels;
529 const int BufDftNumEl = 2*DestDftSize*NumScans*NumChannels;
530 float *BufSpatial = NULL, *BufDft = NULL, *Modulation = NULL, *Ptr;
532 fftwf_iodim Dims[1], HowManyDims[1];
534 int i, Scan, Channel, Success = 0;
538 || !(BufSpatial = (
float *)fftwf_malloc(
sizeof(
float)*BufSpatialNumEl))
539 || !(BufDft = (
float *)fftwf_malloc(
sizeof(
float)*BufDftNumEl)))
544 if(!(Modulation = (
float *)
Malloc(
sizeof(
float)*2*DestDftSize)))
547 for(i = 0; i < DestDftSize; i++)
549 Temp =
M_2PI*XStart*i/SrcPadScanSize;
550 Modulation[2*i + 0] = cos(Temp);
551 Modulation[2*i + 1] = sin(Temp);
556 for(Channel = 0; Channel < NumChannels; Channel++)
558 for(Scan = 0; Scan < NumScans; Scan++)
560 for(i = 0; i < SrcScanSize; i++)
561 BufSpatial[i + SrcPadScanSize*(Scan + NumScans*Channel)]
562 = Src[SrcStride*i + SrcScanStride*Scan
563 + SrcChannelStride*Channel];
565 for(; i < SrcPadScanSize; i++)
566 BufSpatial[i + SrcPadScanSize*(Scan + NumScans*Channel)]
567 = Src[SrcStride*(ReflectOffset - i)
568 + SrcScanStride*Scan + SrcChannelStride*Channel];
575 for(i = 0; i < BufDftNumEl; i++)
579 Dims[0].n = SrcPadScanSize;
582 HowManyDims[0].n = NumScans*NumChannels;
583 HowManyDims[0].is = SrcPadScanSize;
584 HowManyDims[0].os = DestDftSize;
586 if(!(Plan = fftwf_plan_guru_dft_r2c(1, Dims, 1, HowManyDims, BufSpatial,
587 (fftwf_complex *)BufDft, FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
591 fftwf_destroy_plan(Plan);
594 for(Channel = 0, Ptr = BufDft; Channel < NumChannels; Channel++)
595 for(Scan = 0; Scan < NumScans; Scan++, Ptr += 2*DestDftSize)
596 for(i = 0; i < SrcDftSize; i++)
598 Ptr[2*i + 0] /= SrcPadScanSize;
599 Ptr[2*i + 1] /= SrcPadScanSize;
604 Temp = SrcPadScanSize / (
M_2PI * PsfSigma);
607 for(i = 0; i < SrcDftSize; i++)
609 if(i <= DestScanSize)
610 Denom = exp(-(i*i)/Temp);
612 Denom = exp(-((DestPadScanSize - i)*(DestPadScanSize - i))/Temp);
614 Denom *= SrcPadScanSize;
616 for(Channel = 0; Channel < NumChannels; Channel++)
617 for(Scan = 0; Scan < NumScans; Scan++)
619 BufDft[2*(i + DestDftSize*(Scan + NumScans*Channel)) + 0]
621 BufDft[2*(i + DestDftSize*(Scan + NumScans*Channel)) + 1]
629 for(Channel = 0, Ptr = BufDft; Channel < NumChannels; Channel++)
630 for(Scan = 0; Scan < NumScans; Scan++, Ptr += 2*DestDftSize)
631 for(i = 0; i < SrcDftSize; i++)
634 Temp = Ptr[2*i + 0]*Modulation[2*i + 0]
635 - Ptr[2*i + 1]*Modulation[2*i + 1];
636 Ptr[2*i + 1] = Ptr[2*i + 0]*Modulation[2*i + 1]
637 + Ptr[2*i + 1]*Modulation[2*i + 0];
642 Dims[0].n = DestPadScanSize;
645 HowManyDims[0].n = NumScans*NumChannels;
646 HowManyDims[0].is = DestDftSize;
647 HowManyDims[0].os = DestPadScanSize;
649 if(!(Plan = fftwf_plan_guru_dft_c2r(1, Dims, 1, HowManyDims,
650 (fftwf_complex *)BufDft, BufSpatial,
651 FFTW_ESTIMATE | FFTW_DESTROY_INPUT)))
655 fftwf_destroy_plan(Plan);
658 for(Channel = 0; Channel < NumChannels; Channel++)
660 for(Scan = 0; Scan < NumScans; Scan++)
662 for(i = 0; i < DestScanSize; i++)
663 Dest[DestStride*i + DestScanStride*Scan
664 + DestChannelStride*Channel]
665 = BufSpatial[i + DestPadScanSize*(Scan + NumScans*Channel)];
675 fftwf_free(BufSpatial);
706 int DestHeight,
float YStart,
707 const float *Src,
int SrcWidth,
int SrcHeight,
int NumChannels,
713 unsigned long StartTime, StopTime;
716 if(!Dest || DestWidth < SrcWidth || DestHeight < SrcHeight || !Src
717 || SrcWidth <= 0 || SrcHeight <= 0 || NumChannels <= 0 || PsfSigma < 0
718 || !(Buf = (
float *)
Malloc(
sizeof(
float)*SrcWidth*DestHeight*3)))
724 if(!FourierScaleScan(Buf, SrcWidth, 1, SrcWidth*DestHeight, DestHeight,
725 Src, SrcWidth, 1, SrcWidth*SrcHeight, SrcHeight,
726 SrcWidth, 3, YStart, PsfSigma, Boundary))
730 if(!FourierScaleScan(Dest, 1, DestWidth, DestWidth*DestHeight, DestWidth,
731 Buf, 1, SrcWidth, SrcWidth*DestHeight, SrcWidth,
732 DestHeight, 3, XStart, PsfSigma, Boundary))
736 printf(
"CPU Time: %.3f s\n\n", 0.001*(StopTime - StartTime));