33 #define TRIG_TABLE_SIZE 256
35 #define EXP_TABLE_SIZE 1024
39 #define WINDOWRADIUS (1 + NEIGHRADIUS)
41 #define NEIGHDIAMETER (1 + 2*NEIGHRADIUS)
43 #define NEIGHCENTER (NEIGHRADIUS + NEIGHRADIUS*NEIGHDIAMETER)
45 #define NUMNEIGH (NEIGHDIAMETER*NEIGHDIAMETER)
75 static double Rho(
double x,
double y,
double theta,
76 float SigmaTangent,
float SigmaNormal,
float Anisotropy)
80 SigmaNormal = Anisotropy*SigmaNormal + (1 - Anisotropy)*SigmaTangent;
81 t = (cos(theta)*x + sin(theta)*y) / SigmaTangent;
82 n = (-sin(theta)*x + cos(theta)*y) / SigmaNormal;
83 return exp(-0.5*(t*t + n*n));
88 static float RhoFast(
float x,
float y,
float theta,
89 float SigmaTangent,
float SigmaNormal,
float Anisotropy)
94 static int TablesInitialized = 0;
95 static const float ExpArgScale = 37.0236f;
101 if(!TablesInitialized)
105 ExpTable[i] = (
float)exp(-(i - 0.5)/ExpArgScale);
109 CosTable[i] = (float)cos(i/TrigScale);
110 SinTable[i] = (float)sin(i/TrigScale);
113 TablesInitialized = 1;
116 SigmaNormal = Anisotropy*SigmaNormal + (1 - Anisotropy)*SigmaTangent;
118 i = (int)(theta*TrigScale + 0.5f);
119 t = (CosTable[i]*x + SinTable[i]*y) / SigmaTangent;
120 n = (-SinTable[i]*x + CosTable[i]*y) / SigmaNormal;
121 t = (t*t + n*n)*ExpArgScale/2;
123 if(t >= EXP_TABLE_SIZE)
126 return ExpTable[(int)t];
133 static float Window(
float x)
138 return (x/2 - 1)*x*x + 0.66666666666666667f;
171 const double *PsfSamples)
173 const sset *StencilSet;
176 double X, Y, Alpha, Beta, Sum, Mag, MinMag;
177 float RhoSigmaTangent, RhoSigmaNormal;
178 int x, y, m, mx, my, n, nx, ny, Weight, R, Offset;
181 if(!SInterp || !(StencilSet = SInterp->
StencilSet)
195 for(y = 0, Beta = 0; y <=
QUAD_RES; y++)
197 Weight = (y == 0 || y ==
QUAD_RES) ? 1 : 2;
199 Y = ny - 0.5 + ((double)y)/
QUAD_RES;
200 Beta += Weight*(
EvalPhi(StencilSet, S, X, Y)
201 -
EvalPhi(StencilSet, S, X - 1, Y));
204 for(x = 0, Alpha = 0; x <=
QUAD_RES; x++)
206 Weight = (x == 0 || x ==
QUAD_RES) ? 1 : 2;
207 X = nx - 0.5 + ((double)x)/
QUAD_RES;
209 Alpha -= Weight*(
EvalPhi(StencilSet, S, X, Y)
210 -
EvalPhi(StencilSet, S, X, Y - 1));
215 Mag = Alpha*Alpha + Beta*Beta;
228 MinMag = sqrt(MinMag);
241 for(y = -R, Offset = 0; y <= R; y++)
242 for(x = -R; x <= R; x++, Offset++)
243 Sum += PsfSamples[Offset]
244 * Rho(mx - nx - ((
double)x)/
QUAD_RES,
247 RhoSigmaTangent, RhoSigmaNormal,
258 Entry->
Matrix[n] = (
float)InverseA[n];
265 static double *SamplePsf(
double (*Psf)(
double,
double,
const void*),
266 const void *PsfParam,
int R,
double Step)
268 const int W = 2*R + 1;
269 double *Samples = NULL;
273 if(!(Samples = (
double *)
Malloc(
sizeof(
double)*W*W)))
277 Samples[0] = 1/(Step*Step);
279 for(j = -R, Offset = 0; j <= R; j++)
280 for(i = -R; i <= R; i++, Offset++)
281 Samples[Offset] = Psf(Step*i, Step*j, PsfParam);
299 float RhoSigmaTangent,
float RhoSigmaNormal)
302 double *PsfSamples = NULL;
356 static int ConstExtension(
int N,
int i)
401 const int *Stencil,
const sinterp *SInterp,
402 const float *Input,
int InputWidth,
int InputHeight,
403 float ScaleFactor,
int CenteredGrid)
405 int (*Extension)(int, int) = ConstExtension;
406 const int InputNumEl = 3*InputWidth*InputHeight;
408 const float *Matrix, *CoeffPtr;
409 float u[3], uk[3], v[3], c[3*(
NUMNEIGH + 1)], X, Y, Weight, DenomSum;
411 float XStart, YStart, Xp, Yp, WindowWeight;
412 float RhoSigmaTangent, RhoSigmaNormal;
413 int i, ix, iy, k, x, y, m, n, mx, my, nx, ny, S, Success = 0;
416 if(!(Coeff = (
float *)
Malloc(
sizeof(
float)*(
NUMNEIGH + 1)*InputNumEl)))
421 XStart = (1/ScaleFactor - 1
422 + (InputWidth - OutputWidth/ScaleFactor))/2;
423 YStart = (1/ScaleFactor - 1
424 + (InputHeight - OutputHeight/ScaleFactor))/2;
433 for(y = 0, k = 0; y < InputHeight; y++)
434 for(x = 0; x < InputWidth; x++, k++)
436 S = Stencil[x + InputWidth*y];
438 c[0] = Input[3*k + 0];
439 c[1] = Input[3*k + 1];
440 c[2] = Input[3*k + 2];
442 for(m = 3; m < 3*(
NUMNEIGH + 1); m++)
448 if(nx != 0 || ny != 0)
450 i = 3*(Extension(InputWidth, x + nx)
451 + InputWidth*Extension(InputHeight, y - ny));
452 v[0] = Input[i + 0] - c[0];
453 v[1] = Input[i + 1] - c[1];
454 v[2] = Input[i + 2] - c[2];
459 c[3*(m + 1) + 0] += Matrix[m + NUMNEIGH*n]*v[0];
460 c[3*(m + 1) + 1] += Matrix[m + NUMNEIGH*n]*v[1];
461 c[3*(m + 1) + 2] += Matrix[m + NUMNEIGH*n]*v[2];
467 for(m = 0; m < 3*(
NUMNEIGH + 1); m++)
468 Coeff[3*(
NUMNEIGH + 1)*k + m] = c[m];
472 for(y = 0, k = 0; y < OutputHeight; y++)
474 Y = YStart + y/ScaleFactor;
475 iy = (int)ceil(Y - WINDOWRADIUS);
478 WindowWeightY[n] = Window(Y - iy - n);
480 for(x = 0; x < OutputWidth; x++, k += 3)
482 X = XStart + x/ScaleFactor;
483 ix = (int)ceil(X - WINDOWRADIUS);
486 WindowWeightX[n] = Window(X - ix - n);
489 u[0] = u[1] = u[2] = 0;
493 if((iy + my) < 0 || (iy + my) >= InputHeight)
497 i = ix + InputWidth*(iy + my);
501 if((ix + mx) < 0 || (ix + mx) >= InputWidth)
505 CoeffPtr = Coeff + i*3*(
NUMNEIGH + 1);
515 Weight = RhoFast(Xp - nx, -(Yp + ny),
517 RhoSigmaTangent, RhoSigmaNormal,
519 uk[0] += CoeffPtr[3*(n + 1) + 0] * Weight;
520 uk[1] += CoeffPtr[3*(n + 1) + 1] * Weight;
521 uk[2] += CoeffPtr[3*(n + 1) + 2] * Weight;
524 WindowWeight = WindowWeightX[mx] * WindowWeightY[my];
525 DenomSum += WindowWeight;
526 u[0] += WindowWeight * uk[0];
527 u[1] += WindowWeight * uk[1];
528 u[2] += WindowWeight * uk[2];
532 Output[k + 0] = u[0] / DenomSum;
533 Output[k + 1] = u[1] / DenomSum;
534 Output[k + 2] = u[2] / DenomSum;
567 int ScaleFactor,
int CenteredGrid)
570 float *RhoSamples = NULL;
572 double x, y, SampleOffset;
573 float RhoSigmaTangent, RhoSigmaNormal;
574 int SupportWidth, SupportSize;
575 int S, sx, sy, i, m, mx, my, n, nx, ny;
578 if(CenteredGrid && ScaleFactor % 2 == 0)
580 SupportWidth = 2*WINDOWRADIUS*ScaleFactor;
585 SupportWidth = 2*WINDOWRADIUS*ScaleFactor - 1;
589 SupportSize = SupportWidth*SupportWidth;
591 if(!SInterp || !(RhoSamples = (
float *)
Malloc(
sizeof(
float)*
603 for(sy = SupportWidth - 1, i = 0; sy >= 0; sy--)
604 for(sx = 0; sx < SupportWidth; sx++, i++)
606 x = SampleOffset + ((double)sx)/ScaleFactor;
607 y = SampleOffset + ((double)sy)/ScaleFactor;
617 Weight = Rho(x - mx, y - my,
619 RhoSigmaTangent, RhoSigmaNormal,
625 RhoS[n] += Matrix[m + NUMNEIGH*n]*Weight;
632 Weight = Window((
float)x)*Window((
float)y);
635 RhoSamples[i + SupportSize*(n + NUMNEIGH*S)]
636 = (float)(RhoS[n] * Weight);
661 const int *Stencil,
const float *RhoSamples,
662 const float *Input,
int InputWidth,
int InputHeight,
663 int ScaleFactor,
int CenteredGrid)
665 const int OutputWidth = ScaleFactor*InputWidth;
666 const int OutputHeight = ScaleFactor*InputHeight;
667 int (*Extension)(int, int) = ConstExtension;
668 const int InputStride = 3*InputWidth;
669 const int OutputStride = 3*OutputWidth;
670 const float *RhoSamplePtr, *InputPtr;
672 int sx, sy, SampleOffset, SupportWidth, SupportSize, ni;
673 int ix, iy, InteriorLower, InteriorUpperX, InteriorUpperY;
674 int i, i0, i00, x, y, nx, ny, OutputOffset;
677 if(CenteredGrid && ScaleFactor % 2 == 0)
679 SupportWidth = 2*WINDOWRADIUS*ScaleFactor;
680 SampleOffset = WINDOWRADIUS*ScaleFactor - ScaleFactor/2;
684 SupportWidth = 2*WINDOWRADIUS*ScaleFactor - 1;
685 SampleOffset = WINDOWRADIUS*ScaleFactor - 1;
688 SampleOffset -= (ScaleFactor - 1)/2;
691 SupportSize = SupportWidth*SupportWidth;
692 OutputOffset = 3*SampleOffset*(1 + OutputWidth);
695 InteriorLower = (SampleOffset + ScaleFactor - 1)/ScaleFactor;
696 InteriorUpperX = (OutputWidth + SampleOffset
697 - SupportWidth + 1)/ScaleFactor;
698 InteriorUpperY = (OutputHeight + SampleOffset
699 - SupportWidth + 1)/ScaleFactor;
705 if(InteriorUpperY > OutputHeight - NEIGHRADIUS - 1)
706 InteriorUpperY = OutputHeight - NEIGHRADIUS - 1;
708 for(iy = -WINDOWRADIUS; iy < InputHeight +
WINDOWRADIUS; iy++)
709 for(ix = -WINDOWRADIUS; ix < InputWidth +
WINDOWRADIUS; ix++)
711 if(!(InteriorLower <= ix && ix < InteriorUpperX
712 && InteriorLower <= iy && iy < InteriorUpperY))
714 RhoSamplePtr = RhoSamples + SupportSize*
NUMNEIGH*
715 Stencil[(Extension(InputWidth, ix)
716 + InputWidth*Extension(InputHeight, iy))];
721 ni = 3*(Extension(InputWidth, ix + nx)
722 + InputWidth*Extension(InputHeight, iy - ny));
723 v[0] = Input[ni + 0];
724 v[1] = Input[ni + 1];
725 v[2] = Input[ni + 2];
726 y = ScaleFactor*iy - SampleOffset;
728 for(sy = 0; sy < SupportWidth;
729 sy++, y++, RhoSamplePtr += SupportWidth)
730 if(0 <= y && y < OutputHeight)
732 x = ScaleFactor*ix - SampleOffset;
733 i = 3*(x + OutputWidth*y);
735 for(sx = 0; sx < SupportWidth;
737 if(0 <= x && x < OutputWidth)
739 Weight = RhoSamplePtr[sx];
740 Output[i + 0] += Weight*v[0];
741 Output[i + 1] += Weight*v[1];
742 Output[i + 2] += Weight*v[2];
749 RhoSamplePtr = RhoSamples +
750 SupportSize*
NUMNEIGH*Stencil[ix + InputWidth*iy];
751 i00 = 3*(ScaleFactor*ix + OutputWidth*ScaleFactor*iy) - OutputOffset;
752 InputPtr = Input + 3*(ix - NEIGHRADIUS + InputWidth*(iy +
NEIGHRADIUS));
754 for(ny = 0; ny <
NEIGHDIAMETER; ny++, InputPtr -= InputStride)
758 v[0] = InputPtr[nx + 0];
759 v[1] = InputPtr[nx + 1];
760 v[2] = InputPtr[nx + 2];
762 for(sy = 0, i0 = i00; sy < SupportWidth; sy++,
763 i0 += OutputStride, RhoSamplePtr += SupportWidth)
764 for(sx = 0, i = i0; sx < SupportWidth; sx++, i += 3)
766 Weight = RhoSamplePtr[sx];
767 Output[i + 0] += Weight*v[0];
768 Output[i + 1] += Weight*v[1];
769 Output[i + 2] += Weight*v[2];
803 const int *Stencil,
const float *RhoSamples,
804 const float *Input,
int InputWidth,
int InputHeight,
805 int ScaleFactor,
int CenteredGrid,
float PsfSigma,
int NumPasses)
807 const int InputNumEl = 3*InputWidth*InputHeight;
808 const int InterpWidth = ScaleFactor*InputWidth;
809 const int InterpHeight = ScaleFactor*InputHeight;
810 const int InterpNumEl = 3*InterpWidth*InterpHeight;
811 float *Interp = NULL, *Residual = NULL;
813 int i, Pass, Success = 0;
816 if(!Filtered || !Stencil || !RhoSamples || !Input
817 || !(Interp = (
float *)
Malloc(
sizeof(
float)*InterpNumEl))
818 || !(Residual = (
float *)
Malloc(
sizeof(
float)*InputNumEl)))
821 memcpy(Filtered, Input,
sizeof(
float)*InputNumEl);
823 for(i = 0; i < InterpNumEl; i++)
826 printf(
"\n Iteration Residual norm\n -------------------------\n");
828 for(Pass = 0; Pass < NumPasses; Pass++)
832 Input, InputWidth, InputHeight, ScaleFactor, CenteredGrid);
835 Residual, InputWidth, InputHeight, ScaleFactor, CenteredGrid);
838 Input, InputWidth, InputHeight,
839 Interp, InterpWidth, InterpHeight,
840 (
float)ScaleFactor, CenteredGrid, PsfSigma)) < 0)
843 printf(
" %8d %15.8f\n", Pass + 1, MaxResidual);
845 for(i = 0; i < InputNumEl; i++)
846 Filtered[i] += Residual[i];
858 static float Sqr(
float x)
881 const float *Coarse,
int CoarseWidth,
int CoarseHeight,
882 const float *Interp,
int InterpWidth,
int InterpHeight,
883 float ScaleFactor,
int CenteredGrid,
float PsfSigma)
886 int (*Extension)(int, int) = ConstExtension;
887 const int CoarseStride = 3*CoarseWidth;
888 const float PsfRadius = 4*PsfSigma*ScaleFactor;
889 const int PsfWidth = (int)ceil(2*PsfRadius);
890 float *Temp = NULL, *PsfBuf = NULL;
891 float ExpDenom, Weight, Sum[3], DenomSum, MaxResidual = 0;
892 float XStart, YStart, X, Y;
893 int IndexX0, IndexY0, SrcOffset, DestOffset;
897 if(!(Temp = (
float *)
Malloc(
sizeof(
float)*3*CoarseWidth*InterpHeight))
898 || !(PsfBuf = (
float *)
Malloc(
sizeof(
float)*PsfWidth)))
907 XStart = (1/ScaleFactor - 1
908 + (CoarseWidth - InterpWidth/ScaleFactor))/2;
909 YStart = (1/ScaleFactor - 1
910 + (CoarseHeight - InterpHeight/ScaleFactor))/2;
915 ExpDenom = 2 *
Sqr(PsfSigma*ScaleFactor);
917 for(x = 0; x < CoarseWidth; x++)
919 X = (-XStart + x)*ScaleFactor;
920 IndexX0 = (int)ceil(X - PsfRadius);
923 for(n = 0; n < PsfWidth; n++)
924 PsfBuf[n] = (
float)exp(-
Sqr(X - (IndexX0 + n)) / ExpDenom);
926 for(y = 0, SrcOffset = 0, DestOffset = 3*x; y < InterpHeight;
927 y++, SrcOffset += InterpWidth, DestOffset += CoarseStride)
929 Sum[0] = Sum[1] = Sum[2] = DenomSum = 0;
931 for(n = 0; n < PsfWidth; n++)
935 i = 3*(Extension(InterpWidth, IndexX0 + n) + SrcOffset);
937 for(c = 0; c < 3; c++)
938 Sum[c] += Weight * Interp[i + c];
941 for(c = 0; c < 3; c++)
942 Temp[DestOffset + c] = Sum[c] / DenomSum;
946 for(y = 0; y < CoarseHeight; y++,
947 Residual += CoarseStride, Coarse += CoarseStride)
949 Y = (-YStart + y)*ScaleFactor;
950 IndexY0 = (int)ceil(Y - PsfRadius);
953 for(n = 0; n < PsfWidth; n++)
954 PsfBuf[n] = (
float)exp(-
Sqr(Y - (IndexY0 + n)) / ExpDenom);
956 for(x = 0; x < CoarseStride; x += 3)
958 Sum[0] = Sum[1] = Sum[2] = DenomSum = 0;
960 for(n = 0; n < PsfWidth; n++)
962 SrcOffset = x + CoarseStride*Extension(InterpHeight, IndexY0 + n);
966 for(c = 0; c < 3; c++)
967 Sum[c] += Weight * Temp[SrcOffset + c];
970 for(c = 0; c < 3; c++)
972 Residual[x + c] = Coarse[x + c] - Sum[c] / DenomSum;
974 if(fabs(Residual[x + c]) > MaxResidual)
975 MaxResidual = (float)fabs(Residual[x + c]);