Image Interpolation with Contour Stencils

imcoarsen.c

Go to the documentation of this file.
00001 
00020 #include <math.h>
00021 #include <string.h>
00022 #include <ctype.h>
00023 
00024 #include "imageio.h"
00025 
00026 #define VERBOSE 0
00027 
00029 #define NUMSTDS 4
00030 
00031 
00033 typedef struct
00034 {
00036     uint32_t *Data;
00038     int Width;
00040     int Height;
00041 } image;
00042 
00043 typedef enum
00044 {
00045     BOUNDARY_CONSTANT = 0,
00046     BOUNDARY_HSYMMETRIC = 1,
00047     BOUNDARY_WSYMMETRIC = 2
00048 } boundaryhandling;
00049 
00051 typedef struct
00052 {    
00054     char *InputFile;
00056     char *OutputFile;
00058     int JpegQuality;
00060     int CenteredGrid;
00062     boundaryhandling Boundary;
00064     float ScaleFactor;
00066     float PsfSigma;
00067 } programparams;
00068 
00069 
00070 int ParseParams(programparams *Param, int argc, char *argv[]);
00071 int Coarsen(image v, image u, programparams Param);
00072 
00074 void PrintHelpMessage()
00075 {
00076     printf("Image coarsening utility, P. Getreuer 2010-2011\n\n");
00077     printf("Usage: imcoarsen [options] <input file> <output file>\n\n"
00078             "Only " READIMAGE_FORMATS_SUPPORTED " images are supported.\n\n");
00079     printf("Options:\n");
00080     printf("   -x <number>  the coarsening factor (>= 1.0, may be non-integer)\n");
00081     printf("   -p <number>  sigma_h, the blur size of the Gaussian point spread function\n"
00082            "                in units of output pixels.\n");            
00083     printf("   -b <ext>     extension to use for boundary handling, choices for <ext> are\n");
00084     printf("                const        constant extension\n");
00085     printf("                hsym         half-sample symmetric (default)\n");
00086     printf("                wsym         whole-sample symmetric\n");
00087     printf("   -g <grid>    grid to use for resampling, choices for <grid> are\n"
00088            "                centered     grid with centered alignment (default)\n"
00089            "                topleft      the top-left anchored grid\n\n");
00090 #ifdef LIBJPEG_SUPPORT
00091     printf("   -q <number>  quality for saving JPEG images (0 to 100)\n\n");
00092 #endif
00093     printf("Example: coarsen by factor 2.5\n"
00094         "   imcoarsen -x 2.5 -p 0.35 frog.bmp coarse.bmp\n");
00095 }
00096 
00097 
00098 int main(int argc, char *argv[])
00099 {
00100     programparams Param;
00101     image u = {NULL, 0, 0}, v = {NULL, 0, 0};
00102     int Status = 1;
00103     
00104     
00105     if(!ParseParams(&Param, argc, argv))
00106         return 0;
00107             
00108     /* Read the input image */
00109     if(!(u.Data = (uint32_t *)ReadImage(&u.Width, &u.Height, Param.InputFile,
00110         IMAGEIO_U8 | IMAGEIO_RGBA)))
00111         goto Catch;
00112 
00113     if(Param.ScaleFactor >= u.Width || Param.ScaleFactor >= u.Height)
00114     {
00115         ErrorMessage("Image is too small for scale factor.\n");
00116         goto Catch;
00117     }
00118     
00119     /* Allocate the output image */
00120     v.Width = (int)ceil(u.Width / Param.ScaleFactor);
00121     v.Height = (int)ceil(u.Height / Param.ScaleFactor);
00122 #if VERBOSE > 0
00123     printf("%dx%d input --> %dx%d output\n", u.Width, u.Height, v.Width, v.Height);
00124 #endif
00125     
00126     if(!(v.Data = (uint32_t *)Malloc(sizeof(uint32_t)*
00127         ((long int)v.Width)*((long int)v.Height))))
00128         goto Catch;
00129        
00130     /* Convolution followed by downsampling */
00131     if(!Coarsen(v, u, Param))
00132         goto Catch;  
00133     
00134     /* Write the output image */
00135     if(!WriteImage(v.Data, v.Width, v.Height, Param.OutputFile, 
00136         IMAGEIO_U8 | IMAGEIO_RGBA, Param.JpegQuality))
00137         goto Catch;
00138 #if VERBOSE > 0
00139     else
00140         printf("Output written to \"%s\".\n", Param.OutputFile);
00141 #endif
00142     
00143     Status = 0; /* Finished successfully, set exit status to zero. */
00144     
00145 Catch:
00146     Free(v.Data);
00147     Free(u.Data);
00148     return Status;
00149 }
00150 
00151 
00152 float Sqr(float x)
00153 {
00154     return x*x;
00155 }
00156 
00163 static int ConstExtension(int N, int i)
00164 {
00165     if(i < 0)
00166         return 0;
00167     else if(i >= N)
00168         return N - 1;
00169     else
00170         return i;
00171 }
00172 
00173 
00180 static int HSymExtension(int N, int i)
00181 {
00182     while(1)
00183     {
00184         if(i < 0)
00185             i = -1 - i;
00186         else if(i >= N)        
00187             i = (2*N - 1) - i;
00188         else
00189             return i;
00190     }
00191 }
00192 
00193 
00200 static int WSymExtension(int N, int i)
00201 {
00202     while(1)
00203     {
00204         if(i < 0)
00205             i = -i;
00206         else if(i >= N)        
00207             i = (2*N - 2) - i;
00208         else
00209             return i;
00210     }
00211 }
00212 
00213 
00214 int (*ExtensionMethod[3])(int, int) = 
00215     {ConstExtension, HSymExtension, WSymExtension};
00216 
00217 
00218 int Coarsen(image v, image u, programparams Param)
00219 {
00220     int (*Extension)(int, int) = ExtensionMethod[Param.Boundary];
00221     const float PsfRadius = NUMSTDS*Param.PsfSigma*Param.ScaleFactor;
00222     const int PsfWidth = (PsfRadius == 0) ? 1 : (int)ceil(2*PsfRadius);
00223     float *Temp = NULL, *PsfBuf = NULL;
00224     float ExpDenom, Weight, Sum[4], DenomSum;
00225     float XStart, YStart, X, Y;
00226     uint32_t Pixel;
00227     int IndexX0, IndexY0, SrcOffset, DestOffset;
00228     int x, y, n, c, Success = 0;
00229     
00230     
00231     if(!(Temp = (float *)Malloc(sizeof(float)*4*v.Width*u.Height))
00232         || !(PsfBuf = (float *)Malloc(sizeof(float)*PsfWidth)))
00233         goto Catch;
00234     
00235     if(Param.CenteredGrid)
00236     {
00237         XStart = (1/Param.ScaleFactor - 1)/2;
00238         YStart = (1/Param.ScaleFactor - 1)/2;
00239     }
00240     else
00241         XStart = YStart = 0;
00242     
00243     ExpDenom = 2 * Sqr(Param.PsfSigma*Param.ScaleFactor);
00244     
00245     for(x = 0; x < v.Width; x++)
00246     {
00247         X = (-XStart + x)*Param.ScaleFactor;
00248         IndexX0 = (int)floor(X - PsfRadius + 0.5f);
00249         DenomSum = 0;
00250         
00251         /* Evaluate the PSF */
00252         for(n = 0; n < PsfWidth; n++)
00253         {
00254             PsfBuf[n] = Sqr(X - (IndexX0 + n));
00255             
00256             if(!n || PsfBuf[n] < DenomSum)
00257                 DenomSum = PsfBuf[n];
00258         }
00259         
00260         if(ExpDenom > 0)            
00261             for(n = 0; n < PsfWidth; n++)
00262                 PsfBuf[n] = (float)exp((DenomSum - PsfBuf[n]) / ExpDenom);
00263         else
00264             PsfBuf[0] = 1;
00265         
00266         DenomSum = 0;
00267         
00268         for(n = 0; n < PsfWidth; n++)
00269             DenomSum += PsfBuf[n];
00270         
00271         for(y = 0, SrcOffset = 0, DestOffset = x; y < u.Height; 
00272             y++, SrcOffset += u.Width, DestOffset += v.Width)
00273         {
00274             Sum[0] = Sum[1] = Sum[2] = Sum[3] = 0;
00275             
00276             for(n = 0; n < PsfWidth; n++)
00277             {
00278                 Weight = PsfBuf[n];
00279                 Pixel = u.Data[Extension(u.Width, IndexX0 + n) + SrcOffset];
00280                 
00281                 for(c = 0; c < 4; c++)
00282                     Sum[c] += (float)((uint8_t *)&Pixel)[c] * Weight;
00283             }
00284             
00285             for(c = 0; c < 4; c++)
00286                 Temp[4*DestOffset + c] = Sum[c] / DenomSum;
00287         }
00288     }
00289     
00290     for(y = 0; y < v.Height; y++, v.Data += v.Width)
00291     {     
00292         Y = (-YStart + y)*Param.ScaleFactor;
00293         IndexY0 = (int)floor(Y - PsfRadius + 0.5f);
00294         DenomSum = 0;
00295         
00296         /* Evaluate the PSF */
00297         for(n = 0; n < PsfWidth; n++)
00298         {
00299             PsfBuf[n] = Sqr(Y - (IndexY0 + n));
00300             
00301             if(!n || PsfBuf[n] < DenomSum)
00302                 DenomSum = PsfBuf[n];
00303         }
00304         
00305         if(ExpDenom > 0)            
00306             for(n = 0; n < PsfWidth; n++)
00307                 PsfBuf[n] = (float)exp((DenomSum - PsfBuf[n]) / ExpDenom);
00308         else
00309             PsfBuf[0] = 1;
00310         
00311         DenomSum = 0;
00312         
00313         for(n = 0; n < PsfWidth; n++)
00314             DenomSum += PsfBuf[n];
00315         
00316         for(x = 0; x < v.Width; x++)
00317         {
00318             Sum[0] = Sum[1] = Sum[2] = Sum[3] = 0;
00319             
00320             for(n = 0; n < PsfWidth; n++)
00321             {
00322                 SrcOffset = x + v.Width*Extension(u.Height, IndexY0 + n);
00323                 Weight = PsfBuf[n];
00324                 
00325                 for(c = 0; c < 4; c++)
00326                     Sum[c] += Temp[4*SrcOffset + c] * Weight;
00327             }
00328             
00329             for(c = 0; c < 4; c++)
00330                 ((uint8_t *)&Pixel)[c] = (int)(Sum[c] / DenomSum + 0.5f);
00331             
00332             v.Data[x] = Pixel;
00333         }
00334     }
00335     
00336     Success = 1;
00337 Catch:
00338     Free(PsfBuf);
00339     Free(Temp);
00340     return Success;
00341 }
00342 
00343 
00344 int ParseParams(programparams *Param, int argc, char *argv[])
00345 {
00346     static char *DefaultOutputFile = (char *)"out.bmp";
00347     char *OptionString;
00348     char OptionChar;
00349     int i;
00350 
00351     
00352     if(argc < 2)
00353     {
00354         PrintHelpMessage();
00355         return 0;
00356     }
00357 
00358     /* Set parameter defaults */
00359     Param->InputFile = 0;
00360     Param->OutputFile = DefaultOutputFile;
00361     Param->JpegQuality = 99;
00362     Param->ScaleFactor = 1;
00363     Param->PsfSigma = 0.35f;
00364     Param->CenteredGrid = 1;
00365     Param->Boundary = BOUNDARY_HSYMMETRIC;
00366     
00367     for(i = 1; i < argc;)
00368     {
00369         if(argv[i] && argv[i][0] == '-')
00370         {
00371             if((OptionChar = argv[i][1]) == 0)
00372             {
00373                 ErrorMessage("Invalid parameter format.\n");
00374                 return 0;
00375             }
00376 
00377             if(argv[i][2])
00378                 OptionString = &argv[i][2];
00379             else if(++i < argc)
00380                 OptionString = argv[i];
00381             else
00382             {
00383                 ErrorMessage("Invalid parameter format.\n");
00384                 return 0;
00385             }
00386             
00387             switch(OptionChar)
00388             {
00389             case 'x':
00390                 Param->ScaleFactor = (float)atof(OptionString);
00391 
00392                 if(Param->ScaleFactor < 1)
00393                 {
00394                     ErrorMessage("Invalid scale factor.\n");
00395                     return 0;
00396                 }
00397                 break;
00398             case 'p':
00399                 Param->PsfSigma = (float)atof(OptionString);
00400 
00401                 if(Param->PsfSigma < 0.0)
00402                 {
00403                     ErrorMessage("Point spread blur size must be nonnegative.\n");
00404                     return 0;
00405                 }
00406                 break;
00407             case 'b':
00408                 if(!strcmp(OptionString, "const"))
00409                     Param->Boundary = BOUNDARY_CONSTANT;
00410                 else if(!strcmp(OptionString, "hsym"))
00411                     Param->Boundary = BOUNDARY_HSYMMETRIC;
00412                 else if(!strcmp(OptionString, "wsym"))
00413                     Param->Boundary = BOUNDARY_WSYMMETRIC;
00414                 else
00415                 {
00416                     ErrorMessage("Boundary extension must be either \"const\", \"hsym\", or \"wsym\".\n");
00417                     return 0;
00418                 }
00419                 break;
00420             case 'g':
00421                 if(!strcmp(OptionString, "centered")
00422                     || !strcmp(OptionString, "center"))
00423                     Param->CenteredGrid = 1;
00424                 else if(!strcmp(OptionString, "topleft")
00425                     || !strcmp(OptionString, "top-left"))
00426                     Param->CenteredGrid = 0;
00427                 else
00428                 {
00429                     ErrorMessage("Grid must be either \"centered\" or \"topleft\".\n");
00430                     return 0;
00431                 }                
00432                 break;
00433                 
00434 #ifdef LIBJPEG_SUPPORT
00435             case 'q':
00436                 Param->JpegQuality = atoi(OptionString);
00437 
00438                 if(Param->JpegQuality <= 0 || Param->JpegQuality > 100)
00439                 {
00440                     ErrorMessage("JPEG quality must be between 0 and 100.\n");
00441                     return 0;
00442                 }
00443                 break;
00444 #endif
00445             case '-':
00446                 PrintHelpMessage();
00447                 return 0;
00448             default:
00449                 if(isprint(OptionChar))
00450                     ErrorMessage("Unknown option \"-%c\".\n", OptionChar);
00451                 else
00452                     ErrorMessage("Unknown option.\n");
00453 
00454                 return 0;
00455             }
00456 
00457             i++;
00458         }
00459         else
00460         {
00461             if(!Param->InputFile)
00462                 Param->InputFile = argv[i];
00463             else
00464                 Param->OutputFile = argv[i];
00465 
00466             i++;
00467         }
00468     }
00469     
00470     if(!Param->InputFile)
00471     {
00472         PrintHelpMessage();
00473         return 0;
00474     }
00475 
00476     return 1;
00477 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines