Image Interpolation with Contour Stencils

cwinterp.c

Go to the documentation of this file.
00001 
00060 #include <stdio.h>
00061 #include <stdlib.h>
00062 #include <string.h>
00063 #include <math.h>
00064 
00065 #include "basic.h"
00066 #include "cwinterp.h"
00067 #include "fitsten.h"
00068 #include "invmat.h"
00069 #include "nninterp.h"
00070 #include "drawline.h"
00071 
00072 
00074 #define NUMSTENCILS         8
00075 
00077 #define NEIGHRADIUS     1
00078 #define NEIGHDIAMETER   (2*NEIGHRADIUS+1)
00079 #define NUMNEIGH        (NEIGHDIAMETER*NEIGHDIAMETER)
00080 
00089 #define CORRECTION_IGNOREBITS   3
00090 
00092 #define INPUT_FRACBITS          8
00093 
00094 #define PSI_FRACBITS            12
00095 
00096 #define OUTPUT_FRACBITS         (INPUT_FRACBITS + PSI_FRACBITS)
00097 
00099 #define FIXED_ONE(N)    (1 << (N))
00100 
00101 #define FIXED_HALF(N)   (1 << ((N) - 1))
00102 
00103 
00114 #define PIXEL_STRIDE    3
00115 
00116 
00117 /* Generic macros */
00118 
00120 #define CLAMP(X,A,B)    (((X) < (A)) ? (A) : (((X) > (B)) ? (B) : (X)))
00121 
00123 #define ROUNDCLAMP(X,A,B) (((X) < (A)) ? (A) : (((X) > (B)) ? (B) : ROUND(X)))
00124 
00125 #ifndef M_2PI
00126 
00127 #define M_2PI       6.283185307179586476925286766559
00128 #endif
00129 
00130 
00131 /* Orientation in radians of each stencil */
00132 static const double StencilOrientation[NUMSTENCILS] = {-1.178097245096172,
00133     -0.785398163397448, -0.392699081698724, 0.0, 0.392699081698724, 
00134     0.785398163397448, 1.178097245096172, 1.570796326794897};
00135     
00136     
00138 static double Psf(double x, double y, cwparams Param)
00139 {
00140     double SigmaSqr = Param.PsfSigma*Param.PsfSigma;
00141     return exp(-(x*x + y*y)/(2.0*SigmaSqr))/(M_2PI*SigmaSqr);
00142 }
00143 
00144 
00146 static double Phi(double x, double y,
00147     double theta, double PhiSigmaTangent, double PhiSigmaNormal)
00148 {
00149     double t, n;
00150     
00151     /* Oriented Gaussian */
00152     t = (cos(theta)*x + sin(theta)*y) / PhiSigmaTangent;
00153     n = (-sin(theta)*x + cos(theta)*y) / PhiSigmaNormal;
00154     
00155     return exp(-0.5*(t*t + n*n));
00156 }
00157 
00158 
00160 static float CubicBSpline(float x)
00161 {
00162     x = (float)fabs(x);
00163 
00164     if(x < 1)
00165         return (x/2 - 1)*x*x + 0.66666666666666667f;
00166     else if(x < 2)
00167     {
00168         x = 2 - x;
00169         return x*x*x/6;
00170     }
00171     else
00172         return 0;
00173 }
00174 
00175 
00177 static double Window(double x, double y)
00178 {
00179     double Temp;
00180     
00181     x *= 2.0/(NEIGHRADIUS + 1.0);
00182     y *= 2.0/(NEIGHRADIUS + 1.0);
00183     
00184     /* Cubic B-spline */
00185     if(-2.0 < x && x < 2.0 && -2.0 < y && y < 2.0)
00186     {
00187         x = fabs(x);
00188         Temp = fabs(1.0 - x);
00189         x = 1.0 - x + (x*x*x - 2.0*Temp*Temp*Temp)/6.0;
00190         
00191         y = fabs(y);
00192         Temp = fabs(1.0 - y);
00193         y = 1.0 - y + (y*y*y - 2.0*Temp*Temp*Temp)/6.0;
00194         return (x * y) * 4.0/((NEIGHRADIUS + 1.0)*(NEIGHRADIUS + 1.0));
00195     }
00196     else
00197         return 0.0;
00198 }
00199 
00200 
00202 static void QuadraturePoint(double *Weight, double *Abscissa, int Index, int NumPanels)
00203 {
00204     switch(Index % 3)
00205     {
00206     case 0:
00207         *Weight = (Index == 0 || Index == NumPanels)? 0.25 : 0.5;
00208         *Abscissa = Index;
00209         break;
00210     case 1:
00211         *Weight = 1.25;
00212         /* Abscissa location is Index - (3.0/sqrt(5.0) - 1.0)/2.0 */
00213         *Abscissa = Index - 1.70820393249936919e-1; 
00214         break;
00215     case 2:
00216         *Weight = 1.25;
00217         /* Abscissa location is Index + (3.0/sqrt(5.0) - 1.0)/2.0 */
00218         *Abscissa = Index + 1.70820393249936919e-1;
00219         break;
00220     }
00221 }
00222 
00223 
00225 static double PsfPhiConvolution(int x, int y, double Theta, cwparams Param)
00226 {
00227     /* Integrate over the square [-R,R]x[-R,R] */
00228     const double R = 4.0*Param.PsfSigma;
00229     /* Number of panels along each dimension, must be divisible by 3 */
00230     const int NumPanels = 3*16;
00231     const double PanelSize = 2.0*R/NumPanels;
00232     double Integral = 0.0, Slice = 0.0;
00233     double u, v, wu, wv;
00234     int IndexX, IndexY;
00235     
00236     
00237     /* Specially handle the case where PSF is Dirac delta */
00238     if(Param.PsfSigma == 0.0)
00239         return Phi(x, y, Theta, Param.PhiSigmaTangent, Param.PhiSigmaNormal);
00240     
00241     /* Approximate 2D integral */
00242     for(IndexY = 0; IndexY <= NumPanels; IndexY++)
00243     {
00244         QuadraturePoint(&wv, &v, IndexY, NumPanels);
00245         v = PanelSize*v - R;
00246         
00247         for(Slice = 0.0, IndexX = 0; IndexX <= NumPanels; IndexX++)
00248         {
00249             QuadraturePoint(&wu, &u, IndexX, NumPanels);
00250             u = PanelSize*u - R;
00251             Slice += wu*( Psf(u, v, Param) * 
00252                 Phi(x - u, y - v, Theta, Param.PhiSigmaTangent, 
00253                 Param.PhiSigmaNormal) );
00254         }
00255         
00256         Integral += wv*Slice;
00257     }
00258     
00259     Integral *= PanelSize*PanelSize;
00260     return Integral; 
00261 }
00262 
00263 
00265 static int ComputeMatrices(double *InverseA, cwparams Param)
00266 {
00267     double *A = NULL;
00268     double CosTheta, SinTheta;
00269     int m, mx, my, n, nx, ny, S;
00270     int Status = 0;
00271     
00272 
00273     if(!(A = (double *)Malloc(sizeof(double)*NUMNEIGH*NUMNEIGH)))
00274         goto Catch;
00275 
00276     for(S = 0; S < NUMSTENCILS; S++)
00277     {
00278         CosTheta = cos(StencilOrientation[S]);
00279         SinTheta = sin(StencilOrientation[S]);
00280 
00281         for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
00282         for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
00283             for(my = -NEIGHRADIUS, m = 0; my <= NEIGHRADIUS; my++)
00284             for(mx = -NEIGHRADIUS; mx <= NEIGHRADIUS; mx++, m++)
00285             {
00286                 A[m + NUMNEIGH*n] = PsfPhiConvolution(mx - nx, my - ny, 
00287                     StencilOrientation[S], Param);
00288             }
00289 
00290         /* Compute the inverse of A */
00291         if(!InvertMatrix(InverseA + S*(NUMNEIGH*NUMNEIGH), A, NUMNEIGH))
00292             goto Catch;
00293     }
00294     
00295     Status = 1;
00296 Catch:  /* This label is used for error handling.  If something went wrong
00297         above (which may be out of memory or a computation error), then
00298         execution jumps to this point to clean up and exit. */
00299     Free(A);
00300     return Status;
00301 }
00302 
00303 
00304 #include "imageio.h"
00305 
00323 int32_t *PreCWInterp(cwparams Param)
00324 {
00325     int32_t *Psi = NULL;
00326     const int ScaleFactor = (int)ceil(Param.ScaleFactor);
00327     const int SupportRadius = (NEIGHRADIUS+1)*ScaleFactor - 1;
00328     const int SupportWidth = 2*SupportRadius + 1;
00329     const int SupportSize = SupportWidth*SupportWidth;    
00330     double *InverseA = NULL;
00331     double x, y, Wxy, Psi0, Psim, XStart, YStart, WSum;
00332     int S, sx, sy, i, m0, m, mx, my, n, nx, ny, Success = 0;
00333     
00334     
00335     if(!(Psi = (int32_t *)Malloc(sizeof(int32_t)*SupportSize*NUMNEIGH*NUMSTENCILS))
00336         || !(InverseA = (double *)Malloc(sizeof(double)*NUMNEIGH*NUMNEIGH*NUMSTENCILS)))
00337         goto Catch;
00338     
00339     /* Compute the matrices, the results are stored in InverseA. */
00340     if(!ComputeMatrices(InverseA, Param))
00341         goto Catch;
00342     
00343     if(Param.CenteredGrid)
00344     {
00345         XStart = (1/Param.ScaleFactor - 1)/2;
00346         YStart = (1/Param.ScaleFactor - 1)/2;
00347     }
00348     else
00349         XStart = YStart = 0;
00350     
00351     m0 = NEIGHRADIUS + NEIGHRADIUS*NEIGHDIAMETER;
00352     
00353     /* Precompute the samples of the Psi functions */
00354     for(S = 0; S < NUMSTENCILS; S++)
00355         for(i = 0, sy = -SupportRadius; sy <= SupportRadius; sy++)
00356             for(sx = -SupportRadius; sx <= SupportRadius; sx++, i++)
00357             {
00358                 /* Compute the sum of window translates.  This sum should be
00359                    exactly constant, but there can be small variations.  We
00360                    divide the Psi samples computed below by WSum to compensate.
00361                  */
00362                 for(ny = -(int)floor((sy + SupportRadius)/ScaleFactor), WSum = 0;
00363                     ny <= (2*NEIGHRADIUS + 1) && sy + ny*ScaleFactor <= SupportRadius; ny++)
00364                     for(nx = -(int)floor((sx + SupportRadius)/ScaleFactor);
00365                         nx <= (2*NEIGHRADIUS + 1) && sx + nx*ScaleFactor <= SupportRadius; nx++)
00366                     {
00367                         x = XStart + nx + ((double)sx)/((double)ScaleFactor);
00368                         y = YStart + ny + ((double)sy)/((double)ScaleFactor);
00369                         WSum += ROUND(Window(x,y)*FIXED_ONE(PSI_FRACBITS))
00370                             / (double)FIXED_ONE(PSI_FRACBITS);
00371                     }
00372                                 
00373                 x = XStart + ((double)sx)/((double)ScaleFactor);
00374                 y = YStart + ((double)sy)/((double)ScaleFactor);
00375                 Psi0 = Wxy = Window(x, y);
00376                 
00377                 for(my = -NEIGHRADIUS, m = 0; my <= NEIGHRADIUS; my++)
00378                 for(mx = -NEIGHRADIUS; mx <= NEIGHRADIUS; mx++, m++)
00379                 {
00380                     if(m != m0)
00381                     {
00382                         Psim = 0.0;
00383                         
00384                         for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
00385                         for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
00386                             Psim += InverseA[m + NUMNEIGH*(n + NUMNEIGH*S)]
00387                                 * Phi(x - nx, y - ny,
00388                                 StencilOrientation[S], Param.PhiSigmaTangent,
00389                                 Param.PhiSigmaNormal);
00390 
00391                         Psim *= Wxy;
00392                         Psi0 -= Psim;
00393                         
00394                         Psi[i + SupportSize*(m + NUMNEIGH*S)] = 
00395                             (int32_t)ROUND((Psim/WSum)*FIXED_ONE(PSI_FRACBITS));
00396                     }
00397                 }
00398                 
00399                 Psi[i + SupportSize*(m0 + NUMNEIGH*S)] = 
00400                     (int32_t)ROUND((Psi0/WSum)*FIXED_ONE(PSI_FRACBITS));
00401             }
00402     
00403     Success = 1;
00404 Catch:  /* This label is used for error handling.  If something went wrong
00405         above (which may be out of memory or a computation error), then
00406         execution jumps to this point to clean up and exit. */
00407     Free(InverseA);
00408     if(!Success && Psi)
00409     {
00410         Free(Psi);
00411         Psi = NULL;
00412     }
00413     return Psi;
00414 }
00415 
00416 
00432 static void CWFirstPass(int32_t *Interpolation, int ScaleFactor, const int32_t *Input,
00433     int InputWidth, int InputHeight, const int *Stencil, const int32_t *Psi)
00434 {
00435     const int32_t *PsiPtr, *SrcWindow;
00436     int32_t *DestWindow;
00437     
00438     const int Pad = 2;
00439     const int SampleRange = (NEIGHRADIUS+1)*ScaleFactor - 1;
00440     const int SampleWidth = 2*SampleRange + 1;
00441     
00442     const int OutputWidth = ScaleFactor*InputWidth;
00443     const int DestWindowJump = PIXEL_STRIDE*(OutputWidth - SampleWidth);
00444     const int DestStep = PIXEL_STRIDE*ScaleFactor;
00445     const int DestJump = PIXEL_STRIDE*(ScaleFactor-1)*OutputWidth + 2*Pad*DestStep;
00446     const int SrcWindowJump = PIXEL_STRIDE*(InputWidth - NEIGHDIAMETER);
00447     const int SrcJump = 2*PIXEL_STRIDE*Pad;
00448     const int StencilJump = 2*Pad;
00449     
00450     int x, y, NeighX, NeighY, SampleX, SampleY;
00451     int32_t cr, cg, cb;
00452 
00453     
00454     Interpolation += PIXEL_STRIDE*(Pad*ScaleFactor - SampleRange)*(1 + OutputWidth);
00455     Input += PIXEL_STRIDE*(Pad - NEIGHRADIUS)*(1 + InputWidth);
00456     Stencil += Pad*(1 + InputWidth);
00457     
00458     for(y = InputHeight - 2*Pad; y; y--, 
00459         Stencil += StencilJump, Input += SrcJump, Interpolation += DestJump)
00460     for(x = InputWidth - 2*Pad; x; x--, 
00461         Stencil++, Input += PIXEL_STRIDE, Interpolation += DestStep)
00462     {
00463         PsiPtr = Psi + *Stencil;
00464         SrcWindow = Input;
00465         
00466         for(NeighY = NEIGHDIAMETER; NeighY; NeighY--, SrcWindow += SrcWindowJump)
00467         for(NeighX = NEIGHDIAMETER; NeighX; NeighX--, SrcWindow += PIXEL_STRIDE)
00468         {
00469             cr = SrcWindow[0];
00470             cg = SrcWindow[1];
00471             cb = SrcWindow[2];
00472             DestWindow = Interpolation;
00473             SampleY = SampleWidth;
00474             
00475             for(SampleY = SampleWidth; SampleY; 
00476                 SampleY--, DestWindow += DestWindowJump, PsiPtr += SampleWidth)
00477             for(SampleX = 0; SampleX < SampleWidth; 
00478                 SampleX++, DestWindow += PIXEL_STRIDE)
00479             {
00480                 int32_t Temp = PsiPtr[SampleX];
00481                 DestWindow[0] += cr * Temp;
00482                 DestWindow[1] += cg * Temp;
00483                 DestWindow[2] += cb * Temp;
00484             }
00485         }
00486     }
00487 }
00488 
00489 
00505 static void CWRefinementPass(int32_t *Interpolation, int ScaleFactor, 
00506     const int32_t *Residual, int InputWidth, int InputHeight,
00507     const int *Stencil, const int32_t *Sample)
00508 {
00509     const int Pad = 4;
00510 
00511     const int32_t *SamplePtr, *SrcWindow;
00512     int32_t *DestWindow;
00513     const int SampleRange = (NEIGHRADIUS+1)*ScaleFactor - 1;
00514     const int SampleWidth = 2*SampleRange + 1;
00515     const int SampleSize = SampleWidth*SampleWidth;
00516     
00517     const int OutputWidth = ScaleFactor*InputWidth;
00518     const int DestWindowJump = PIXEL_STRIDE*(OutputWidth - SampleWidth);
00519     const int DestStep = PIXEL_STRIDE*ScaleFactor;
00520     const int DestJump = PIXEL_STRIDE*(ScaleFactor-1)*OutputWidth + 2*Pad*DestStep;
00521     const int SrcWindowJump = PIXEL_STRIDE*(InputWidth - NEIGHDIAMETER);
00522     const int SrcJump = 2*PIXEL_STRIDE*Pad;
00523     const int StencilJump = 2*Pad;
00524     
00525     int x, y, NeighX, NeighY, SampleX, SampleY;
00526     int32_t cr, cg, cb;
00527 
00528     
00529     Interpolation += PIXEL_STRIDE*(Pad*ScaleFactor - SampleRange)*(1 + OutputWidth);
00530     Residual += PIXEL_STRIDE*(Pad - NEIGHRADIUS)*(1 + InputWidth);
00531     Stencil += Pad*(1 + InputWidth);
00532 
00533     for(y = InputHeight - 2*Pad; y; y--, 
00534         Stencil += StencilJump, Residual += SrcJump, Interpolation += DestJump)
00535     for(x = InputWidth - 2*Pad; x; x--, 
00536         Stencil++, Residual += PIXEL_STRIDE, Interpolation += DestStep)
00537     {
00538         SamplePtr = Sample + *Stencil;
00539         SrcWindow = Residual;
00540         
00541         for(NeighY = NEIGHDIAMETER; NeighY; NeighY--, SrcWindow += SrcWindowJump)
00542         for(NeighX = NEIGHDIAMETER; NeighX; NeighX--, SrcWindow += PIXEL_STRIDE)
00543         {
00544             cr = SrcWindow[0];
00545             cg = SrcWindow[1];
00546             cb = SrcWindow[2];
00547             
00548             if( ((cr >> CORRECTION_IGNOREBITS) && (-cr >> CORRECTION_IGNOREBITS)) 
00549                 || ((cg >> CORRECTION_IGNOREBITS) && (-cg >> CORRECTION_IGNOREBITS)) 
00550                 || ((cb >> CORRECTION_IGNOREBITS) && (-cb >> CORRECTION_IGNOREBITS)) )
00551             {
00552                 DestWindow = Interpolation;
00553                 SampleY = SampleWidth;
00554                 
00555                 for(SampleY = SampleWidth; SampleY; 
00556                     SampleY--, DestWindow += DestWindowJump, SamplePtr += SampleWidth)
00557                 for(SampleX = 0; SampleX < SampleWidth; 
00558                     SampleX++, DestWindow += PIXEL_STRIDE)
00559                 {
00560                     int32_t Temp = SamplePtr[SampleX];
00561                     DestWindow[0] += cr * Temp;
00562                     DestWindow[1] += cg * Temp;
00563                     DestWindow[2] += cb * Temp;
00564                 }
00565             }
00566             else
00567                 SamplePtr += SampleSize;
00568         }
00569     }
00570 }
00571 
00572 
00579 static int ConstExtension(int N, int i)
00580 {
00581     if(i < 0)
00582         return 0;
00583     else if(i >= N)
00584         return N - 1;
00585     else
00586         return i;
00587 }
00588 
00589 
00590 static float Sqr(float x)
00591 {
00592     return x*x;
00593 }
00594 
00595 
00597 static int32_t CWResidual(int32_t *Residual, const int32_t *Interpolation,
00598         const int32_t *Input, int CoarseWidth, int CoarseHeight, cwparams Param)
00599 {    
00600     int Pad = 4;
00601     const int ScaleFactor = (int)ceil(Param.ScaleFactor);
00602     const int InterpWidth = ScaleFactor*CoarseWidth;
00603     const int InterpHeight = ScaleFactor*CoarseHeight;
00604     const int CoarseStride = 3*CoarseWidth;
00605     const float PsfRadius = (float)(4*Param.PsfSigma*ScaleFactor);
00606     const int PsfWidth = (int)ceil(2*PsfRadius);
00607     float *Temp = NULL, *PsfBuf = NULL;
00608     float ExpDenom, Weight, Sum[3], DenomSum;
00609     float XStart, YStart, X, Y;
00610     int IndexX0, IndexY0, SrcOffset, DestOffset;
00611     int x, y, i, n, c, Success = 0;
00612     int x1, x2;
00613     int32_t ResNorm = 0;
00614     
00615     
00616     if(!(Temp = (float *)Malloc(sizeof(float)*3*CoarseWidth*InterpHeight))
00617         || !(PsfBuf = (float *)Malloc(sizeof(float)*PsfWidth)))
00618         goto Catch;
00619     
00620     if(Param.CenteredGrid)
00621     {
00622         XStart = (1.0f/ScaleFactor - 1)/2;
00623         YStart = (1.0f/ScaleFactor - 1)/2;
00624     }
00625     else
00626         XStart = YStart = 0;
00627     
00628     if(Param.PsfSigma)
00629         ExpDenom = 2 * Sqr((float)(Param.PsfSigma*ScaleFactor));
00630     else
00631         ExpDenom = 2 * Sqr(1e-2f*ScaleFactor);
00632 
00633     if(Pad < ScaleFactor)
00634         Pad = ScaleFactor;
00635     
00636     for(x = 0; x < CoarseWidth; x++)
00637     {
00638         X = (-XStart + x)*ScaleFactor;            
00639         IndexX0 = (int)ceil(X - PsfRadius);
00640         
00641         /* Evaluate the PSF */
00642         for(n = 0; n < PsfWidth; n++)
00643             PsfBuf[n] = (float)exp(-Sqr(X - (IndexX0 + n)) / ExpDenom);
00644         
00645         for(y = 0, SrcOffset = 0, DestOffset = 3*x; y < InterpHeight; 
00646             y++, SrcOffset += InterpWidth, DestOffset += CoarseStride)
00647         {
00648             Sum[0] = Sum[1] = Sum[2] = DenomSum = 0;
00649             
00650             for(n = 0; n < PsfWidth; n++)
00651             {
00652                 Weight = PsfBuf[n];
00653                 DenomSum += Weight;
00654                 i = 3*(ConstExtension(InterpWidth, IndexX0 + n) + SrcOffset);
00655                 
00656                 for(c = 0; c < 3; c++)
00657                     Sum[c] += Weight * Interpolation[i + c];
00658             }
00659             
00660             for(c = 0; c < 3; c++)
00661                 Temp[DestOffset + c] = Sum[c] / DenomSum;
00662         }
00663     }
00664     
00665     x1 = 3*Pad;
00666     x2 = CoarseStride - 3*Pad;
00667     
00668     for(y = 0; y < CoarseHeight; y++, 
00669         Residual += CoarseStride, Input += CoarseStride)
00670     {   
00671         if(!(y >= Pad && y < CoarseHeight-Pad))
00672             continue;
00673         
00674         Y = (-YStart + y)*ScaleFactor;
00675         IndexY0 = (int)ceil(Y - PsfRadius);
00676             
00677         /* Evaluate the PSF */
00678         for(n = 0; n < PsfWidth; n++)
00679             PsfBuf[n] = (float)exp(-Sqr(Y - (IndexY0 + n)) / ExpDenom);
00680                 
00681         for(x = x1; x < x2; x += 3)
00682         {
00683             Sum[0] = Sum[1] = Sum[2] = DenomSum = 0;
00684             
00685             for(n = 0; n < PsfWidth; n++)
00686             {
00687                 SrcOffset = x + CoarseStride*ConstExtension(InterpHeight, IndexY0 + n);
00688                 Weight = PsfBuf[n];
00689                 DenomSum += Weight;
00690                 
00691                 for(c = 0; c < 3; c++)
00692                     Sum[c] += Weight * Temp[SrcOffset + c];
00693             }
00694             
00695             DenomSum *= FIXED_ONE(PSI_FRACBITS);
00696             
00697             for(c = 0; c < 3; c++)
00698             {
00699                 Sum[c] = Input[x + c] - Sum[c] / DenomSum;
00700                 Residual[x + c] = (int32_t)ROUND(Sum[c]);
00701                                 
00702                 if(abs(Residual[x + c]) > ResNorm)
00703                     ResNorm = abs(Residual[x + c]);
00704             }
00705         }
00706     }
00707     
00708     Success = 1;
00709 Catch:
00710     Free(PsfBuf);
00711     Free(Temp);
00712     return (Success) ? ResNorm : -1;
00713 }
00714 
00715 
00734 static void ConvertInput(int32_t *FixedRgb, const uint32_t *Input, int InputWidth, 
00735     int InputHeight, int Padding)
00736 {
00737     const uint8_t *InputPtr = (uint8_t *)Input;
00738     const int InputStride = 4*InputWidth;
00739     const int Stride = PIXEL_STRIDE*(InputWidth + 2*Padding);
00740     int32_t r, g, b;
00741     int i, Row;
00742     
00743     
00744     FixedRgb += Padding*Stride;
00745     
00746     for(Row = InputHeight; Row; Row--, InputPtr += InputStride)
00747     {
00748         r = ((int32_t)InputPtr[0]) << INPUT_FRACBITS;
00749         g = ((int32_t)InputPtr[1]) << INPUT_FRACBITS;
00750         b = ((int32_t)InputPtr[2]) << INPUT_FRACBITS;
00751         
00752         /* Pad left side by copying pixel */
00753         for(i = Padding; i; i--)
00754         {
00755             *(FixedRgb++) = r;
00756             *(FixedRgb++) = g;
00757             *(FixedRgb++) = b;
00758         }
00759         
00760         /* Convert the interior of the image */
00761         for(i = 0; i < InputStride; i += 4)
00762         {
00763             *(FixedRgb++) = ((int32_t)InputPtr[i+0]) << INPUT_FRACBITS;
00764             *(FixedRgb++) = ((int32_t)InputPtr[i+1]) << INPUT_FRACBITS;
00765             *(FixedRgb++) = ((int32_t)InputPtr[i+2]) << INPUT_FRACBITS;
00766         }
00767         
00768         r = ((int32_t)InputPtr[i-4]) << INPUT_FRACBITS;
00769         g = ((int32_t)InputPtr[i-3]) << INPUT_FRACBITS;
00770         b = ((int32_t)InputPtr[i-2]) << INPUT_FRACBITS;
00771         
00772         /* Pad right side by copying pixel */
00773         for(i = Padding; i; i--)
00774         {
00775             *(FixedRgb++) = r;
00776             *(FixedRgb++) = g;
00777             *(FixedRgb++) = b;
00778         }
00779     }
00780     
00781     /* Pad bottom by copying rows */
00782     for(Row = Padding; Row; Row--, FixedRgb += Stride)
00783         memcpy(FixedRgb, FixedRgb - Stride, sizeof(int32_t)*Stride);
00784     
00785     FixedRgb -= Stride*(InputHeight + Padding);
00786     
00787     /* Pad top by coping rows */
00788     for(Row = Padding; Row; Row--, FixedRgb -= Stride)
00789         memcpy(FixedRgb - Stride, FixedRgb, sizeof(int32_t)*Stride);
00790 }
00791 
00792 
00816 static void ConvertOutput(uint32_t *Output, int OutputWidth, int OutputHeight, 
00817     const int32_t *FixedRgb, int Width)
00818 {
00819     uint8_t *OutputPtr = (uint8_t *)Output;
00820     const int CroppedStride = PIXEL_STRIDE*OutputWidth, Stride = PIXEL_STRIDE*Width;
00821     int32_t r, g, b;
00822     int i, Row;
00823     
00824     
00825     for(Row = OutputHeight; Row; Row--, FixedRgb += Stride)
00826         for(i = 0; i < CroppedStride; i += PIXEL_STRIDE)
00827         {
00828             /* Convert fixed-point values to integer */
00829             r = (FixedRgb[i+0] + FIXED_HALF(OUTPUT_FRACBITS)) >> OUTPUT_FRACBITS;
00830             g = (FixedRgb[i+1] + FIXED_HALF(OUTPUT_FRACBITS)) >> OUTPUT_FRACBITS;
00831             b = (FixedRgb[i+2] + FIXED_HALF(OUTPUT_FRACBITS)) >> OUTPUT_FRACBITS;
00832             
00833             /* Clamp range to [0, 255] and store in Output */
00834             *(OutputPtr++) = CLAMP(r, 0, 255);
00835             *(OutputPtr++) = CLAMP(g, 0, 255);
00836             *(OutputPtr++) = CLAMP(b, 0, 255);
00837             *(OutputPtr++) = 0xFF;
00838         }
00839 }
00840 
00841 
00851 int CWInterp(uint32_t *Output, const uint32_t *Input,
00852     int InputWidth, int InputHeight, const int32_t *Psi, cwparams Param)
00853 {
00854     const int ScaleFactor = (int)ceil(Param.ScaleFactor);
00855     const int SupportRadius = (NEIGHRADIUS+1)*ScaleFactor - 1;
00856     const int SupportWidth = 2*SupportRadius + 1;
00857     const int SupportSize = SupportWidth*SupportWidth;
00858     const int StencilMul = NUMNEIGH*SupportSize;    
00859     int *Stencil = NULL;
00860     int32_t *InputFixed = NULL, *OutputFixed = NULL, *Residual = NULL;
00861     unsigned long StartTime, StopTime;
00862     int i, PadInput, pw, ph, Success = 0;
00863     int32_t ResNorm;
00864     
00865     
00866     /* Iterative refinement is unnecessary if PSF is the Dirac delta */
00867     if(Param.PsfSigma == 0.0)
00868         Param.RefinementSteps = 0;
00869     
00870     PadInput = 4 + (ScaleFactor + 1)/2;
00871     pw = InputWidth + 2*PadInput;
00872     ph = InputHeight + 2*PadInput;
00873     
00874     if( !(OutputFixed = (int32_t *)Malloc(sizeof(int32_t)*
00875             PIXEL_STRIDE*pw*ScaleFactor*ph*ScaleFactor))
00876         || !(InputFixed = (int32_t *)Malloc(sizeof(int32_t)*PIXEL_STRIDE*pw*ph))
00877         || !(Residual = (int32_t *)Malloc(sizeof(int32_t)*PIXEL_STRIDE*pw*ph))
00878         || !(Stencil = (int *)Malloc(sizeof(int)*pw*ph)) )
00879         goto Catch;
00880 
00881     /* Start timing */
00882     StartTime = Clock();
00883 
00884     /* Convert 32-bit RGBA pixels to integer array */
00885     ConvertInput(InputFixed, Input, InputWidth, InputHeight, PadInput);
00886     
00887     /* Select the best-fitting contour stencils */
00888     if(!FitStencils(Stencil, InputFixed, pw, ph, StencilMul))
00889         goto Catch;
00890     
00891     memset(OutputFixed, 0, sizeof(int32_t)*
00892         3*pw*ScaleFactor*ph*ScaleFactor);
00893     memset(Residual, 0, sizeof(int32_t)*3*pw*ph);
00894     
00895     printf("\n  Iteration   Residual norm\n  -------------------------\n");
00896     
00897     /* First interpolation pass */
00898     CWFirstPass(OutputFixed, ScaleFactor, InputFixed, pw, ph, Stencil, Psi);
00899     
00900     /* Iterative refinement */
00901     for(i = 1; i <= Param.RefinementSteps; i++)
00902     {
00903         /* Compute the residual */
00904         if((ResNorm = CWResidual(Residual, OutputFixed, InputFixed, 
00905             pw, ph, Param)) < 0.0)
00906             goto Catch;
00907         
00908         printf("  %8d %15.8f\n", i, ResNorm/(255.0*256.0));
00909         
00910         /* Interpolation refinement pass */
00911         CWRefinementPass(OutputFixed, ScaleFactor, Residual, pw, ph, Stencil, Psi);
00912     }
00913     
00914     /* Convert output integer array to 32-bit RGBA */
00915     ConvertOutput(Output, InputWidth*ScaleFactor, InputHeight*ScaleFactor,
00916         OutputFixed + PIXEL_STRIDE*PadInput*ScaleFactor*(1 + pw*ScaleFactor),
00917         pw*ScaleFactor);
00918     
00919     /* The final interpolation is now complete, stop timing. */
00920     StopTime = Clock();
00921 
00922     /* Compute the residual norm of the final interpolation.  This
00923     computation is not included in the CPU timing since it is for
00924     information purposes only. */
00925     ResNorm = CWResidual(Residual, OutputFixed, InputFixed, pw, ph, Param);
00926     printf("  %8d %15.8f\n\n", Param.RefinementSteps + 1, ResNorm/(255.0*256.0));
00927     
00928     /* Display the CPU time spent performing the interpolation. */
00929     printf("  CPU time: %.3f s\n\n", 0.001*(StopTime - StartTime));
00930 
00931     Success = 1;
00932     
00933 Catch:  /* This label is used for error handling.  If something went wrong
00934         above (which may be out of memory or a computation error), then
00935         execution jumps to this point to clean up and exit. */
00936     Free(Stencil);
00937     Free(Residual);
00938     Free(InputFixed);
00939     Free(OutputFixed);
00940     return Success;
00941 }
00942 
00943 
00945 #define ROUNDCLAMP(X,A,B) (((X) < (A)) ? (A) : (((X) > (B)) ? (B) : ROUND(X)))    
00946     
00947 
00948 /* The following parameters define the number of fractional bits used for 
00949    signed 32-bit fixedpoint arithmetic in CWSynth2Fixed.  These parameters
00950    should be large enough for reasonable precision but small enough to
00951    avoid overflow.  Additionally, the implementation constraints on 
00952    choosing these parameters are
00953  
00954        WINDOW_FRACBITS >= UK_FRACBITS,
00955        TRIG_FRACBITS + XY_FRACBITS - PHITN_FRACBITS >= 1,
00956        COEFF_FRACBITS + PHI_FRACBITS - UK_FRACBITS >= 1.
00957  */
00958 #define XY_FRACBITS         15
00959 #define TRIG_FRACBITS       10
00960 #define PHITN_FRACBITS      9
00961 #define PHI_FRACBITS        10
00962 #define COEFF_FRACBITS      10
00963 #define WINDOW_FRACBITS     10
00964 #define UK_FRACBITS         10
00965 
00966 #define ROUND_FIXED(X,N)    (((X) + FIXED_HALF(N)) >> (N))
00967 #define FLOAT_TO_FIXED(X,N) ((int32_t)ROUND((X) * FIXED_ONE(N)))
00968     
00970 int CWArbitraryInterp(uint32_t *Output, int OutputWidth, int OutputHeight,
00971     const int32_t *Input, int InputWidth, int InputHeight, 
00972     const int *Stencil, const double *InverseA, cwparams Param)
00973 {
00974     /*int (*Extension)(int, int) = ExtensionMethod[Param.Boundary];*/
00975     int (*Extension)(int, int) = ConstExtension;
00976     const int InputNumEl = 3*InputWidth*InputHeight;
00977     const int ExpTableSize = 1024;
00978     const double ExpArgScale = 37.0236;
00979     const double PhiTScale = sqrt(ExpArgScale/2)/Param.PhiSigmaTangent;
00980     const double PhiNScale = sqrt(ExpArgScale/2)/Param.PhiSigmaNormal;
00981     
00982     int32_t *Coeff = NULL, *CoeffPtr, *ExpTable = NULL;
00983     
00984     float X, Y, XStart, YStart;     
00985     float Temp, cr[NUMNEIGH], cg[NUMNEIGH], cb[NUMNEIGH];        
00986     int32_t v0[3], v[3], WindowWeight, WindowWeightX[4], WindowWeightY[4];
00987     int32_t Xpf, Ypf, Weight, uk[3], u[3], DenomSum;
00988     int32_t CosTableTf[NUMSTENCILS], SinTableTf[NUMSTENCILS];
00989     int32_t CosTableNf[NUMSTENCILS], SinTableNf[NUMSTENCILS];
00990     int32_t Pixel;    
00991     int i, k, x, y, m, n, mx, my, nx, ny, S, Success = 0;
00992     int ix, iy, Cur, Offset;
00993 
00994     
00995     if(!(Coeff = (int32_t *)Malloc(sizeof(int32_t)*(NUMNEIGH + 1)*InputNumEl))
00996         || !(ExpTable = (int32_t *)Malloc(sizeof(int32_t)*ExpTableSize)))
00997         goto Catch;
00998     
00999     if(Param.CenteredGrid)
01000     {
01001         XStart = (float)(1/Param.ScaleFactor - 1)/2;
01002         YStart = (float)(1/Param.ScaleFactor - 1)/2;
01003     }
01004     else
01005         XStart = YStart = 0;
01006     
01007     for(S = 0; S < NUMSTENCILS; S++)
01008     {
01009         CosTableTf[S] = FLOAT_TO_FIXED(
01010             PhiTScale * cos(StencilOrientation[S]), TRIG_FRACBITS);
01011         SinTableTf[S] = FLOAT_TO_FIXED(
01012             PhiTScale * sin(StencilOrientation[S]), TRIG_FRACBITS);
01013         CosTableNf[S] = FLOAT_TO_FIXED(
01014             PhiNScale * cos(StencilOrientation[S]), TRIG_FRACBITS);
01015         SinTableNf[S] = FLOAT_TO_FIXED(
01016             PhiNScale * sin(StencilOrientation[S]), TRIG_FRACBITS);
01017     }
01018     
01019     for(i = 0; i < ExpTableSize; i++)
01020         ExpTable[i] = FLOAT_TO_FIXED(exp( -(double)(i + 0.5f)/ExpArgScale), PHI_FRACBITS);
01021 
01022     for(y = 0, k = 0, CoeffPtr = Coeff; y < InputHeight; y++)
01023         for(x = 0; x < InputWidth; x++, k++, CoeffPtr += 3*(NUMNEIGH + 1))
01024         {
01025             S = NUMNEIGH*Stencil[k];
01026             
01027             v0[0] = Input[3*k + 0];
01028             v0[1] = Input[3*k + 1];
01029             v0[2] = Input[3*k + 2];
01030              
01031             for(m = 0; m < NUMNEIGH; m++)
01032                 cr[m] = 0;
01033             for(m = 0; m < NUMNEIGH; m++)
01034                 cg[m] = 0;
01035             for(m = 0; m < NUMNEIGH; m++)
01036                 cb[m] = 0;
01037             
01038             for(ny = -NEIGHRADIUS, n = 0; ny <= NEIGHRADIUS; ny++)
01039             {
01040                 Offset = InputWidth*Extension(InputHeight, y + ny);
01041                 
01042                 for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n++)
01043                 {
01044                     if(n != 1 + (2*NEIGHRADIUS + 1))
01045                     {                    
01046                         i = 3*(Extension(InputWidth, x + nx) + Offset);
01047                         v[0] = Input[i + 0];
01048                         v[1] = Input[i + 1];
01049                         v[2] = Input[i + 2];
01050                         
01051                         for(m = 0; m < NUMNEIGH; m++)
01052                         {
01053                             Temp = (float)InverseA[m + NUMNEIGH*(n + S)];
01054                             cr[m] += Temp * (v[0] - v0[0]);
01055                             cg[m] += Temp * (v[1] - v0[1]);
01056                             cb[m] += Temp * (v[2] - v0[2]);
01057                         }
01058                     }
01059                 }
01060             }
01061             
01062             /* The first three coeff values have UK_FRACBITS fractional bits */
01063             CoeffPtr[0] = v0[0] << (UK_FRACBITS - INPUT_FRACBITS);
01064             CoeffPtr[1] = v0[1] << (UK_FRACBITS - INPUT_FRACBITS);
01065             CoeffPtr[2] = v0[2] << (UK_FRACBITS - INPUT_FRACBITS);
01066             
01067             /* The other values have COEFF_FRACBITS fractional bits */
01068             for(m = 0; m < NUMNEIGH; m++)
01069             {
01070                 CoeffPtr[3*(m + 1) + 0] = FLOAT_TO_FIXED(cr[m] 
01071                     / FIXED_ONE(INPUT_FRACBITS), COEFF_FRACBITS);
01072                 CoeffPtr[3*(m + 1) + 1] = FLOAT_TO_FIXED(cg[m] 
01073                     / FIXED_ONE(INPUT_FRACBITS), COEFF_FRACBITS);
01074                 CoeffPtr[3*(m + 1) + 2] = FLOAT_TO_FIXED(cb[m] 
01075                     / FIXED_ONE(INPUT_FRACBITS), COEFF_FRACBITS);
01076             }
01077             
01078         }
01079     
01080     for(y = 0, k = 0; y < OutputHeight; y++)
01081     {
01082         Y = YStart + (float)(y/Param.ScaleFactor);
01083         iy = (int)ceil(Y - 2*NEIGHRADIUS);
01084 
01085         /* Precompute y-factor of the window weights */
01086         for(my = 0; my < 4*NEIGHRADIUS; my++)
01087             WindowWeightY[my] = FLOAT_TO_FIXED(
01088                 CubicBSpline(Y - (iy + my)), WINDOW_FRACBITS);
01089 
01090         for(x = 0; x < OutputWidth; x++, k++)
01091         {
01092             X = XStart + (float)(x/Param.ScaleFactor);
01093             ix = (int)ceil(X - 2*NEIGHRADIUS);
01094 
01095             /* Precompute x-factor of the window weights */
01096             for(mx = 0; mx < 4*NEIGHRADIUS; mx++)
01097                 WindowWeightX[mx] = FLOAT_TO_FIXED(
01098                     CubicBSpline(X - (ix + mx)), WINDOW_FRACBITS);        
01099             
01100             DenomSum = 0;
01101             u[0] = u[1] = u[2] = 0;
01102             
01103             for(my = 0, Ypf = (int32_t)ROUND((Y - iy) * FIXED_ONE(XY_FRACBITS)); my < 4*NEIGHRADIUS; 
01104                 my++, Ypf -= FIXED_ONE(XY_FRACBITS))
01105             if((iy + my) >= 0 && (iy + my) < InputHeight)
01106             {
01107                 for(mx = 0, Xpf = (int32_t)ROUND((X - ix) * FIXED_ONE(XY_FRACBITS)), 
01108                     i = ix + InputWidth*(iy + my), CoeffPtr = Coeff + i*3*(NUMNEIGH + 1); 
01109                     mx < 4*NEIGHRADIUS; mx++, i++, CoeffPtr += 3*(NUMNEIGH + 1), Xpf -= FIXED_ONE(XY_FRACBITS))
01110                 {
01111                     if((ix + mx) < 0 || (ix + mx) >= InputWidth)
01112                         continue;
01113                     
01114                     /* WindowWeight has 2*WINDOW_FRACBITS fractional bits. */
01115                     WindowWeight = (WindowWeightX[mx] * WindowWeightY[my]);                    
01116                     /* DenomSum is computed using 2*WINDOW_FRACBITS. */
01117                     DenomSum += WindowWeight;                    
01118                     /* Now reduce to WindowWeight to WINDOW_FRACBITS. */
01119                     WindowWeight = (WindowWeight + FIXED_HALF(WINDOW_FRACBITS)) 
01120                         >> WINDOW_FRACBITS;
01121                     
01122                     if(!WindowWeight)
01123                         continue;
01124                                         
01125                     S = Stencil[i];
01126                                         
01127                     uk[0] = CoeffPtr[0];
01128                     uk[1] = CoeffPtr[1];
01129                     uk[2] = CoeffPtr[2];
01130                     
01131                     for(ny = -NEIGHRADIUS, n = 3; ny <= NEIGHRADIUS; ny++)
01132                         for(nx = -NEIGHRADIUS; nx <= NEIGHRADIUS; nx++, n += 3)
01133                         {
01134                             int32_t phit, phin;
01135                             
01136                             /* The tables use TRIG_FRACBITS fractional bits,
01137                                and X and Y use XY_FRACBITS, so the products
01138                                have (TRIG_FRACBITS + XY_FRACBITS) fractional
01139                                bits.  The shift reduces the result to 
01140                                PHITN_FRACBITS. */   
01141                             phit = ( CosTableTf[S]*(Xpf - nx*FIXED_ONE(XY_FRACBITS))
01142                                 + SinTableTf[S]*(Ypf - ny*FIXED_ONE(XY_FRACBITS)) 
01143                                 + FIXED_HALF(TRIG_FRACBITS + XY_FRACBITS - PHITN_FRACBITS)) 
01144                                 >> (TRIG_FRACBITS + XY_FRACBITS - PHITN_FRACBITS);
01145                             phin = ( -SinTableNf[S]*(Xpf - nx*FIXED_ONE(XY_FRACBITS))
01146                                 + CosTableNf[S]*(Ypf - ny*FIXED_ONE(XY_FRACBITS)) 
01147                                 + FIXED_HALF(TRIG_FRACBITS + XY_FRACBITS - PHITN_FRACBITS))
01148                                 >> (TRIG_FRACBITS + XY_FRACBITS - PHITN_FRACBITS);
01149                              
01150                             /* phit and phin have PHITN_FRACBITS, so the
01151                                products have 2*PHITN_FRACBITS.  The result is
01152                                shifted by 2*PHITN_FRACBITS to convert to 
01153                                quantity (by floor rounding) to an integer. */
01154                             Cur = (phit*phit + phin*phin) >> (2*PHITN_FRACBITS);
01155                                 
01156                             if(Cur >= ExpTableSize)
01157                                 continue;
01158                             
01159                             /* Compute exp(-Cur) via table look up.  The result
01160                                has PHI_FRACBITS fractional bits. */                            
01161                             Weight = ExpTable[Cur];
01162   
01163                             /* The Coeff values have COEFF_FRACBITS fractional
01164                                bits and Weight has PHI_FRACBITS.  The products
01165                                are shifted so that the result has 
01166                                WINDOW_FRACBITS. */
01167                             uk[0] += (CoeffPtr[n + 0] * Weight
01168                                 + FIXED_HALF(COEFF_FRACBITS + PHI_FRACBITS - WINDOW_FRACBITS)) 
01169                                 >> (COEFF_FRACBITS + PHI_FRACBITS - UK_FRACBITS);
01170                             uk[1] += (CoeffPtr[n + 1] * Weight
01171                                 + FIXED_HALF(COEFF_FRACBITS + PHI_FRACBITS - WINDOW_FRACBITS))
01172                                 >> (COEFF_FRACBITS + PHI_FRACBITS - UK_FRACBITS);
01173                             uk[2] += (CoeffPtr[n + 2] * Weight
01174                                 + FIXED_HALF(COEFF_FRACBITS + PHI_FRACBITS - WINDOW_FRACBITS))
01175                                 >> (COEFF_FRACBITS + PHI_FRACBITS - UK_FRACBITS);
01176                         }
01177                     
01178                     /* u is computed using WINDOW_FRACBITS + UK_FRACBITS. */
01179                     u[0] += WindowWeight * uk[0];
01180                     u[1] += WindowWeight * uk[1];
01181                     u[2] += WindowWeight * uk[2];
01182                 }
01183             }           
01184 
01185             if(DenomSum >= FIXED_ONE(2*WINDOW_FRACBITS) - 1)
01186             {
01187                 u[0] = ROUND_FIXED(u[0], WINDOW_FRACBITS + UK_FRACBITS);
01188                 u[1] = ROUND_FIXED(u[1], WINDOW_FRACBITS + UK_FRACBITS);
01189                 u[2] = ROUND_FIXED(u[2], WINDOW_FRACBITS + UK_FRACBITS);
01190             }
01191             else
01192             {
01193                 /* Reduce DenomSum from 2*WINDOW_FRACBITS fractional bits to 
01194                 (WINDOW_FRACBITS + UK_FRACBITS) fractional bits. */
01195 #if WINDOW_FRACBITS > UK_FRACBITS
01196                 DenomSum = (DenomSum + FIXED_HALF(WINDOW_FRACBITS - UK_FRACBITS)) 
01197                     >> (WINDOW_FRACBITS - UK_FRACBITS);
01198 #endif                
01199                 /* u and DenomSum both have (WINDOW_FRACBITS + UK_FRACBITS)
01200                 fractional bits, so the quotient is integer. */
01201                 u[0] = (u[0] + DenomSum/2) / DenomSum;
01202                 u[1] = (u[1] + DenomSum/2) / DenomSum;
01203                 u[2] = (u[2] + DenomSum/2) / DenomSum;
01204             }
01205             
01206             Pixel = 0xFFFFFFFF;
01207             ((uint8_t *)&Pixel)[0] = CLAMP(u[0],0,255);
01208             ((uint8_t *)&Pixel)[1] = CLAMP(u[1],0,255);
01209             ((uint8_t *)&Pixel)[2] = CLAMP(u[2],0,255);
01210             Output[k] = Pixel;
01211         }
01212     }
01213               
01214     Success = 1;
01215 Catch:
01216     Free(ExpTable);
01217     Free(Coeff);
01218     return Success;
01219 }
01220 
01221 
01223 static void AddResidual(int32_t *InputAdjusted, const int32_t *Residual, 
01224     int InputWidth, int InputHeight, int PadInput)
01225 {
01226     const int PadWidth = InputWidth + 2*PadInput;
01227     const int RowEl = 3*InputWidth;
01228     const int PadRowEl = 3*PadWidth;
01229     int i, Row;
01230     
01231     Residual += 3*(PadInput + PadInput*PadWidth);
01232         
01233     for(Row = InputHeight; Row; Row--)
01234     {
01235         for(i = 0; i < RowEl; i++)
01236             InputAdjusted[i] += Residual[i];
01237         
01238         InputAdjusted += RowEl;
01239         Residual += PadRowEl;
01240     }
01241 }
01242 
01243 
01245 static void StencilStripPad(int *Stencil, 
01246     int InputWidth, int InputHeight, int PadInput, int StencilMul)
01247 {
01248     const int PadWidth = InputWidth + 2*PadInput;
01249     int *Src;
01250     int i, Row;
01251     
01252     Src = Stencil + (PadInput + PadInput*PadWidth);
01253         
01254     for(Row = InputHeight; Row; Row--)
01255     {
01256         for(i = 0; i < InputWidth; i++)
01257             Stencil[i] = Src[i] / StencilMul;
01258             
01259         Stencil += InputWidth;
01260         Src += PadWidth;
01261     }
01262 }
01263 
01274 int CWInterpEx(uint32_t *Output, int OutputWidth, int OutputHeight,
01275     const uint32_t *Input, int InputWidth, int InputHeight, 
01276     const int32_t *Psi, cwparams Param)
01277 {
01278     const int ScaleFactor = (int)ceil(Param.ScaleFactor);
01279     const int SupportRadius = (NEIGHRADIUS+1)*ScaleFactor - 1;
01280     const int SupportWidth = 2*SupportRadius + 1;
01281     const int SupportSize = SupportWidth*SupportWidth;
01282     const int StencilMul = NUMNEIGH*SupportSize;
01283     double *InverseA = NULL;
01284     int *Stencil = NULL;
01285     int32_t *InputFixed = NULL, *InputAdjusted = NULL, *OutputFixed = NULL, *Residual = NULL;
01286     unsigned long StartTime, StopTime;
01287     int i, PadInput, pw, ph, Success = 0;
01288     int32_t ResNorm;
01289     
01290     
01291     /* Iterative refinement is unnecessary if PSF is the Dirac delta */
01292     if(Param.PsfSigma == 0.0)
01293         Param.RefinementSteps = 0;
01294     
01295     PadInput = 4 + (ScaleFactor + 1)/2;
01296     pw = InputWidth + 2*PadInput;
01297     ph = InputHeight + 2*PadInput;
01298     
01299     if( !(InverseA = (double *)Malloc(sizeof(double)*NUMNEIGH*NUMNEIGH*NUMSTENCILS))
01300         || !(OutputFixed = (int32_t *)Malloc(sizeof(int32_t)*
01301             PIXEL_STRIDE*pw*ScaleFactor*ph*ScaleFactor))
01302         || !(InputFixed = (int32_t *)Malloc(sizeof(int32_t)*PIXEL_STRIDE*pw*ph))
01303         || !(InputAdjusted = (int32_t *)Malloc(sizeof(int32_t)*PIXEL_STRIDE*InputWidth*InputHeight))
01304         || !(Residual = (int32_t *)Malloc(sizeof(int32_t)*PIXEL_STRIDE*pw*ph))
01305         || !(Stencil = (int *)Malloc(sizeof(int)*pw*ph)) )
01306         goto Catch;
01307     
01308     if(!ComputeMatrices(InverseA, Param))
01309         goto Catch;
01310     
01311     /* Start timing */
01312     StartTime = Clock();
01313 
01314     if(Param.RefinementSteps > 0)
01315     {
01316         /* Convert 32-bit RGBA pixels to integer array */
01317         ConvertInput(InputFixed, Input, InputWidth, InputHeight, PadInput);
01318         
01319         memset(InputAdjusted, 0, sizeof(int32_t)*3*InputWidth*InputHeight);
01320         AddResidual(InputAdjusted, InputFixed, InputWidth, InputHeight, PadInput);
01321         
01322         /* Select the best-fitting contour stencils */
01323         if(!FitStencils(Stencil, InputFixed, pw, ph, StencilMul))
01324             goto Catch;
01325         
01326         memset(OutputFixed, 0, sizeof(int32_t)*
01327             3*pw*ScaleFactor*ph*ScaleFactor);
01328         memset(Residual, 0, sizeof(int32_t)*3*pw*ph);
01329         
01330         printf("\n  Iteration   Residual norm\n  -------------------------\n");
01331         
01332         /* First interpolation pass */
01333         CWFirstPass(OutputFixed, ScaleFactor, InputFixed, pw, ph, Stencil, Psi);
01334         
01335         /* Iterative refinement */
01336         for(i = 1; i <= Param.RefinementSteps; i++)
01337         {
01338             /* Compute the residual */
01339             if((ResNorm = CWResidual(Residual, OutputFixed, InputFixed, 
01340                 pw, ph, Param)) < 0.0)
01341                 goto Catch;
01342             
01343             printf("  %8d %15.8f\n", i, ResNorm/(255.0*256.0));
01344         
01345             AddResidual(InputAdjusted, Residual, InputWidth, InputHeight, PadInput);
01346             
01347             if(i < Param.RefinementSteps)
01348             {
01349                 /* Interpolation refinement pass */
01350                 CWRefinementPass(OutputFixed, ScaleFactor, Residual, pw, ph, Stencil, Psi);
01351             }
01352         }
01353         
01354         StencilStripPad(Stencil, InputWidth, InputHeight, PadInput, StencilMul);
01355     }
01356     else
01357     {
01358         /* Convert 32-bit RGBA pixels to integer array */
01359         ConvertInput(InputAdjusted, Input, InputWidth, InputHeight, 0);
01360         
01361         /* Select the best-fitting contour stencils */
01362         if(!FitStencils(Stencil, InputAdjusted, InputWidth, InputHeight, 1))
01363             goto Catch;
01364     }
01365     
01366     if(!CWArbitraryInterp(Output, OutputWidth, OutputHeight,
01367         InputAdjusted, InputWidth, InputHeight, Stencil, InverseA, Param))
01368         goto Catch;
01369         
01370     /* The final interpolation is now complete, stop timing. */
01371     StopTime = Clock();
01372 
01373     if(Param.RefinementSteps > 1)
01374         printf("  %8d   (not computed)\n\n", Param.RefinementSteps + 1);
01375     
01376     /* Display the CPU time spent performing the interpolation. */
01377     printf("  CPU time: %.3f s\n\n", 0.001*(StopTime - StartTime));
01378 
01379     Success = 1;
01380     
01381 Catch:  /* This label is used for error handling.  If something went wrong
01382         above (which may be out of memory or a computation error), then
01383         execution jumps to this point to clean up and exit. */
01384     Free(Stencil);
01385     Free(Residual);
01386     Free(InputAdjusted);
01387     Free(InputFixed);
01388     Free(OutputFixed);
01389     Free(InverseA);
01390     return Success;
01391 }
01392 
01393 
01395 int DisplayContours(uint32_t *Output, int OutputWidth, int OutputHeight,
01396     uint32_t *Input, int InputWidth, int InputHeight, cwparams Param)
01397 {
01398     const int Pad = 2;
01399     const float LineColor[3] = {0, 0, 0};
01400     int *Stencil = 0;
01401     float dx, dy;
01402     int32_t *InputInt = NULL;
01403     uint32_t Pixel;   
01404     int x, y, S, pw, ph, Success = 0;
01405     
01406     
01407     pw = InputWidth + 2*Pad;
01408     ph = InputHeight + 2*Pad;
01409     
01410     if( !(InputInt = (int32_t *)Malloc(sizeof(int32_t)*3*pw*ph))
01411         || !(Stencil = (int *)Malloc(sizeof(int)*pw*ph)) )
01412         goto Catch;
01413     
01414     /* Convert 32-bit RGBA pixels to integer array */
01415     ConvertInput(InputInt, Input, InputWidth, InputHeight, Pad);
01416     
01417     /* Select the best-fitting contour stencils */
01418     if(!FitStencils(Stencil, InputInt, pw, ph, 1))
01419         goto Catch;
01420     
01421     /* Lighten the image */
01422     for(y = 0; y < InputHeight; y++)
01423         for(x = 0; x < InputWidth; x++)
01424         {
01425             Pixel = Input[x + InputWidth*y];            
01426             ((uint8_t*)&Pixel)[0] = (uint8_t)(((uint8_t*)&Pixel)[0]/2 + 128);
01427             ((uint8_t*)&Pixel)[1] = (uint8_t)(((uint8_t*)&Pixel)[1]/2 + 128);
01428             ((uint8_t*)&Pixel)[2] = (uint8_t)(((uint8_t*)&Pixel)[2]/2 + 128);            
01429             Input[x + InputWidth*y] = Pixel;
01430         }
01431         
01432     /* Nearest neighbor interpolation */
01433     NearestInterp(Output, OutputWidth, OutputHeight, 
01434                   Input, InputWidth, InputHeight,
01435                   (float)Param.ScaleFactor, Param.CenteredGrid);
01436     
01437     /* Draw contour orientation lines */
01438     for(y = 0; y < InputHeight; y++)
01439         for(x = 0; x < InputWidth; x++)
01440         {
01441             S = Stencil[(x + Pad) + pw*(y + Pad)];
01442             dx = (float)cos(StencilOrientation[S])*0.6f;
01443             dy = (float)sin(StencilOrientation[S])*0.6f;
01444             DrawLine(Output, OutputWidth, OutputHeight,
01445                 (float)Param.ScaleFactor*(x - dx + 0.5f) - 0.5f,
01446                 (float)Param.ScaleFactor*(y - dy + 0.5f) - 0.5f,
01447                 (float)Param.ScaleFactor*(x + dx + 0.5f) - 0.5f,
01448                 (float)Param.ScaleFactor*(y + dy + 0.5f) - 0.5f, LineColor);
01449         }
01450 
01451     Success = 1;
01452 Catch:  /* This label is used for error handling.  If something went wrong
01453         above (which may be out of memory or a computation error), then
01454         execution jumps to this point to clean up and exit. */
01455     Free(Stencil);
01456     Free(InputInt);
01457     return Success;
01458 }
01459 
01460     
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines