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);