23 #define JPEGQUALITY                 95 
   25 #define CLAMP(X,A,B)    (((X) <= (A)) ? (A) : (((X) >= (B)) ? (B) : (X))) 
   30     puts(
"Generate a random inpainting mask, P. Getreuer, Y. Wang, 2012\n\n" 
   31         "Syntax: randmask <type> <input> <output>\n");
 
   32     puts(
"where <input> and <output> are "  
   34     puts(
"Choices for <type>\n");
 
   36     "    dots:<r>          Random dots of radius <r>\n" 
   37     "    scribble:<r>      Random scribble with pen of radius <r>\n" 
   38     "    Bernoulli:<p>     Random pixel mask with masking ratio <p>\n" 
   39     "    text              Random text\n");
 
   41         "  randmask scribble:3 input.bmp mask.bmp\n");
 
   45 int Dots(
unsigned char *Mask, 
int Width, 
int Height, 
int PenRadius);
 
   46 int Scribble(
unsigned char *Mask, 
int Width, 
int Height, 
int PenRadius);
 
   47 void RandomText(
unsigned char *Mask, 
int Width, 
int Height);
 
   48 int Bernoulli(
unsigned char *Mask, 
int Width, 
int Height, 
double Ratio);
 
   50 int main(
int argc, 
char **argv)
 
   52     const char *Type, *InputFile, *OutputFile;
 
   54     unsigned char *Image = NULL;
 
   56     int Width, Height, Status = 1;
 
   65     if((ParamString = strchr(argv[1], 
':')))
 
   67         Param = atof(ParamString + 1);
 
   79     if(!(Image = (
unsigned char *)
ReadImage(&Width, &Height, InputFile, 
 
   80         IMAGEIO_GRAYSCALE | IMAGEIO_U8)))
 
   83     memset(Image, 0, ((
long)Width) * ((
long)Height));
 
   88     if(!strcmp(Type, 
"dots"))
 
   90         if(!
Dots(Image, Width, Height, (
int)Param))
 
   93     else if(!strcmp(Type, 
"scribble"))
 
   95         if(!
Scribble(Image, Width, Height, (
int)Param))
 
   98     else if(!strcmp(Type, 
"Bernoulli"))
 
  100         if(!
Bernoulli(Image, Width, Height, Param))
 
  103     else if(!strcmp(Type, 
"text"))
 
  107         fprintf(stderr, 
"Unknown mask type, \"%s\".\n", Type);
 
  112     if(!
WriteImage(Image, Width, Height, OutputFile, 
 
  115         fprintf(stderr, 
"Error writing to \"%s\".\n", OutputFile);
 
  126 unsigned char *MakePen(
int PenRadius)
 
  128     const int PenRadiusSquared = (int)((PenRadius + 0.5f)*(PenRadius + 0.5f));
 
  129     const int PenWidth = 2*PenRadius + 1;    
 
  130     unsigned char *Pen = NULL;    
 
  133     if((Pen = calloc(PenWidth*PenWidth, 
sizeof(
unsigned char))))
 
  134         for(y = -PenRadius, i = 0; y <= PenRadius; y++)
 
  135             for(x = -PenRadius; x <= PenRadius; x++, i++)
 
  136                 if(x*x + y*y <= PenRadiusSquared)
 
  143 void PutPixel(
unsigned char *Image, 
int Width, 
int Height, 
 
  146     if(0 <= x && x < Width && 0 <= y && y < Height)
 
  147         Image[x + Width*y] = 255;
 
  151 void PutPen(
unsigned char *Image, 
int Width, 
int Height, 
 
  152     unsigned char *Pen, 
int PenRadius, 
int x0, 
int y0)
 
  156     for(y = -PenRadius, i = 0; y <= PenRadius; y++)
 
  157         for(x = -PenRadius; x <= PenRadius; x++, i++)
 
  159                 PutPixel(Image, Width, Height, x0 + x, y0 + y);
 
  163 unsigned char GetPixel(
unsigned char *Image, 
 
  164     int Width, 
int Height, 
int x, 
int y)
 
  166     if(0 <= x && x < Width && 0 <= y && y < Height)
 
  167         return Image[x + Width*y];
 
  180 int Dots(
unsigned char *Mask, 
int Width, 
int Height, 
int PenRadius)
 
  182     const long NumPoints = (long)
 
  183         (2 * sqrt(((
float)Width) * ((
float)Height))/PenRadius + 0.5);
 
  184     unsigned char *Pen = NULL;
 
  187     if(!(Pen = MakePen(PenRadius)))
 
  190     for(i = 0; i < NumPoints; i++)
 
  191         PutPen(Mask, Width, Height, Pen, PenRadius,
 
  204 int Bernoulli(
unsigned char *Image, 
int Width, 
int Height, 
double Ratio)
 
  206     const long NumPixels = ((long)Width) * ((long)Height);
 
  209     if(Ratio < 0 || Ratio > 1)
 
  211         fprintf(stderr, 
"Invalid ratio %1.1f " 
  212             "(should be in the interval [0,1]).\n", Ratio);
 
  216     for(i = 0; i < NumPixels; i++) 
 
  234 int Scribble(
unsigned char *Mask, 
int Width, 
int Height, 
int PenRadius)
 
  236     const float Accel = 0.15f;
 
  237     const float Force = 0.1f;
 
  238     const int NumPaths = 20;
 
  239     const long NumPoints = (long)
 
  240         (5 * sqrt(((
float)Width) * ((
float)Height)) + 0.5);
 
  241     unsigned char *Pen = NULL;
 
  242     float (*Path)[2] = NULL, (*BestPath)[2] = NULL;
 
  243     float MeanX, MeanY, Variance, BestVariance = 0;
 
  244     float PosX, PosY, VelocityX, VelocityY, VelocityMag;
 
  248     if(!(Pen = MakePen(PenRadius))
 
  249         || !(Path = 
Malloc(
sizeof(
float)*2*NumPoints))
 
  250         || !(BestPath = 
Malloc(
sizeof(
float)*2*NumPoints)))
 
  253     for(j = 0; j < NumPaths; j++)
 
  260         VelocityMag = (float)sqrt(VelocityX*VelocityX + VelocityY*VelocityY);
 
  261         VelocityX /= VelocityMag;
 
  262         VelocityY /= VelocityMag;
 
  264         for(i = 0; i < NumPoints; i++)
 
  270                 Accel*((float)
rand_normal() + (Width/2 - PosX)*Force/Width);
 
  272                 Accel*((float)
rand_normal() + (Height/2 - PosY)*Force/Height);
 
  274             VelocityMag = (float)sqrt(VelocityX*VelocityX 
 
  275                 + VelocityY*VelocityY);
 
  279                 VelocityX /= VelocityMag;
 
  280                 VelocityY /= VelocityMag;
 
  285             PosX = CLAMP(PosX, 0, Width - 1);
 
  286             PosY = CLAMP(PosY, 0, Height - 1);
 
  288             if((PosX <= 0 && VelocityX < 0)
 
  289                 || (PosX >= Width - 1 && VelocityX > 0))
 
  292             if((PosY <= 0 && VelocityY < 0)
 
  293                 || (PosY >= Height - 1 && VelocityY > 0))
 
  298         for(i = 0, MeanX = MeanY = 0; i < NumPoints; i++)
 
  307         for(i = 0, Variance = 0; i < NumPoints; i++)
 
  308             Variance += (Path[i][0] - MeanX)*(Path[i][0] - MeanX)
 
  309                 + (Path[i][1] - MeanY)*(Path[i][1] - MeanY);
 
  311         if(Variance > BestVariance)
 
  313             BestVariance = Variance;
 
  314             memcpy(BestPath, Path, 
sizeof(
float)*2*NumPoints);
 
  318     for(i = 0; i < NumPoints; i++)
 
  319         PutPen(Mask, Width, Height, Pen, PenRadius,
 
  320             (
int)BestPath[i][0], (
int)BestPath[i][1]);
 
  345     static const char Text0[] =
 
  346     "In the context of digital images, inpainting is used to restore regions " 
  347     "of an image that are corrupted by noise or where the data is missing.  " 
  348     "Inpainting is also used to solve disocclusion, to estimate the scene " 
  349     "behind an obscuring foreground object. Inpainting is an interpolation " 
  350     "problem, filling the unknown region with a condition to agree with the " 
  351     "known image on the boundary.  ";
 
  352     static const char Text1[] = 
 
  353     "However, Laplace's equation is usually unsatisfactory for images since " 
  354     "it is overly smooth.  It cannot recover a step edge passing through the " 
  355     "region.  Total variation (TV) regularization is an effective inpainting " 
  356     "technique which is capable of recovering sharp edges under some " 
  357     "conditions (these conditions will be explained).  The use of TV " 
  358     "regularization was originally developed for image denoising by Rudin, " 
  359     "Osher, and Fatemi [3] and then applied to inpainting by Chan and Shen.  ";
 
  360     static const char Text2[] = 
 
  361     "The first variational approach to the image inpainting problem was " 
  362     "Nitzberg and Mumford's 2.1-D sketch [2], based on a variant of the " 
  363     "Mumford-Shah functional, and the second variational approach was the " 
  364     "work of Masnou and Morel [6], based on solving for level lines with " 
  365     "minimal curvature.  Bertalmio, Sapiro, Caselles, and Ballester [8] " 
  366     "introduced the term \"image inpainting\" in analogy to artistic " 
  367     "inpainting and proposed an anisotropic diffusion PDE model.  ";
 
  368     static const char Text3[] =
 
  369     "TV inpainting prefers straight contours as they have minimal TV, but " 
  370     "this is less successful for recovering curved boundaries.  TV " 
  371     "inpainting can reconstruct a stripe passing through the inpainting " 
  372     "domain, but only if the length to be bridged is less than the stripe " 
  373     "thickness. TV inpainting breaks the stripe if the length is greater.  " 
  374     "TV inpainting prefers straight contours as they have minimal TV, but " 
  375     "this is less successful for recovering curved boundaries.  ";
 
  378     char LineBuffer[1024];
 
  381     for(y = -4; y < Height; y += 19)
 
  394         TextLength = strlen(Text);
 
  400             LineBuffer[j] = Text[i % TextLength];
 
  401             LineBuffer[j + 1] = 
'\0';
 
  404         }
while(j < 1023 && 
TextWidth(LineBuffer) < Width + 5);
 
  407         DrawText(Mask, Width, Height, -2, y, 255, LineBuffer);