Image Interpolation with Contour Stencils
|
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