/*************************************************************************************************************************************/
/* */
/* T O O L S F O R A U T O S T E R E O G R A M G E N E R A T I O N */
/* W I T H T E X T U R E I N T E R P O L A T I O N : */
/* */
/* */
/* Example of an alpha-numeric autostereogram : */
/* */
/* */
/* O-oo::o:-o%o:o:-O-oo::o:-o%o:o:-O-oo::o:-o%o:o:-O-oo::o:-o%o:o:- */
/* -oo::O:.-::oOoo:-oo::O:.-::oOoo:-oo::O:.-::oOoo:-oo::O:.-::oOoo: */
/* :o:-OoO.-:OOo:o::o:-OoO.-:OOo:o::o:-OoO.-:OOo:o::o:-OoO.-:OOo:o: */
/* :o::::-OOOO-:oOo:o::::-OOOO-:oOo-o::::-OOOO-:oOo-o::::-OOOO-:oOo */
/* ::-o-o.o:oO:-oo-::-o-o.ooOo-oo-::-:::-::oOo-oo-::-:::-::oOo-oo-: */
/* :o-::oo::.:oo:Oo:o-::oo:.oooOo:o-::oo:.-ooo-%o:o-::oo:.-ooo-%o:o */
/* ::o-:O:o.o:ooooo::::O::o:o-oOo:--:%o-Ooo-ooO::::-:%o-Ooo-ooO:::: */
/* O-o-oOOoOOo:o:--oo-OOOOoooo:o:-oo-OO%O:oo::o-O-o-:OO%O:oo::o-O-o */
/* -o:-:o::oOo-::O-o::o:::OOo:-::O-o::o::oOo-::::o:-:o:::oOo-::::o: */
/* o-:-oO-o:ooo:o:-::oO::o::ooo:o:-::oO::o::oo::-:OoOOo-:o::oo::-:O */
/* :o-:::%::O:O-O:oo::::O%::O:O-O:oo::::O%::O:o%:.:::::o%%::O:o%:.: */
/* :-:::-oo::%-:-:-:o:::-oo::%-:-:-:o:::-oo::%-:--o:::--ooo::%-:--o */
/* :-o::Ooooo-:-%O-:OO-:Ooooo-:-%O-:OO-:Ooooo-:-O::O-oooooooo-:-O:: */
/* :::ooooOoOoo::o::-oooooOoOoo::o::-oooooOoOoo::o::o:OOoo%oOoo::o: */
/* o:oooo:::Ooo:-oo::oooo:::Ooo:-oo::oooo:::Ooo:-o:::o::::::Ooo:-o: */
/* :o::o::oO-:-.:::o:::o::oO-:-.:::o:::o::oO-:-.::o::o:::o:O-:-.::o */
/* o-oo:O::-oOoO-o:-ooo:O::-oOoO-o:-ooo:O::-oOoO-o-oo-Oo::--oOoO-o- */
/* o-o::oo:oo-::::-:oO::oo:oo-::::-:oO::oo:oo-:::::oo:OOoo:oo-::::: */
/* -o::-o:O-O-:oo-o::-:-o:O-O-:oo-o::-:-o:O-O-:ooo:-:-oo:oO-O-:ooo: */
/* O:Ooo:o:ooo:OoO:OOooo:o:ooo:OoO:OOooo:o:ooo:oo:%ooo::O::ooo:oo:% */
/* o:oO-o:oo::%Ooo:oO:-o::oo::%Ooo:oO:-o::oo:::ooOO--oo:::oo:::ooOO */
/* ::O:o-o:o::oO:-:o:o:-Oo:o::oO:-:o:o:-Oo:o:oO%:%oo:--:Oo:o:oO%:%o */
/* O.-:ooOOoo:ooo%O.:ooOO:ooo-Ooo%O.:oo%Oooo:oooo.-:ooO%Oooo:oooo.- */
/* O.o::-O:oo:o::o--o:.O:oo:o:o:O--o:.Ooo:o:o:O-O.o:o.Ooo:o:o:O-O.o */
/* oOO:-oo::oo%oo-:ooo-oo-ooOO:-o:oo-Oo:OooO:--ooOoo-Oo:OooO:--ooOo */
/* ooo:oO:Ooo:oo%o:ooo:o:OooO:#o:ooO:ooOoo-O:%%o:ooO:ooOoo-O:%%o:oo */
/* oo:ooo-o%-:%o:o:oo:ooo-OO-%ooo-oo:Oo:::%:-%ooo-oo:Oo:::%:-%ooo-o */
/* O:O:o:o:%::Oo:oOO:O:o:o:%::Oo:oOO:O:o:o:%::Oo:oOO:O:o:o:%::Oo:oO */
/* Oo:o:o:-Oo::oo-oOo:o:o:-Oo::oo-oOo:o:o:-Oo::oo-oOo:o:o:-Oo::oo-o */
/* ::::o::::o:ooO-O::::o::::o:ooO-O::::o::::o:ooO-O::::o::::o:ooO-O */
/* :o:-o::o-::::%Oo:o:-o::o-::::%Oo:o:-o::o-::::%Oo:o:-o::o-::::%Oo */
/* :o::::OO%-o::::.:o::::OO%-o::::.:o::::OO%-o::::.:o::::OO%-o::::. */
/* */
/* */
/* Author of '$xtc/stereogra.11$c' : */
/* */
/* Jean-Francois COLONNA (LACTAMME, 20110607144808). */
/* */
/*************************************************************************************************************************************/
#include <stdio.h>
extern void *malloc();
extern int atoi();
extern char *getenv();
#define Get(valeur_de_la_variable,nom_de_la_variable) \
{ \
valeur_de_la_variable = atoi(getenv(nom_de_la_variable)); \
} \
/* Get an environment variable. */
static int dimX=0;
#define Xmin 0
#define Xmax (Xmin + (dimX-1))
/* Definition of the 'OX' axis. */
static int dimY=0;
#define Ymin 0
#define Ymax (Ymin + (dimY-1))
/* Definition of the 'OY' axis. */
#define Dpicture(type,nom) \
type *nom=malloc(dimX*dimY*sizeof(type)) \
/* Definition of a picture as a matrix. */
#define Rpicture(type,nom) \
type *nom \
/* Reference a picture. */
#define IMAGE(image,x,y) \
(*(image + ((((y)-Ymin)*dimX) + ((x)-Xmin)))) \
/* Point access. */
#define COXR(x) \
((int)((x) - Xmin)) \
/* Relative value of an 'X' coordinate. */
#define COXA(x) \
((int)((x) + Xmin)) \
/* "Absolute" value of an 'X' coordinate. */
#define X_SCREEN(x) \
COXA((int)((double)(x)*((double)dimX))) \
/* Put a [0,1] value into X-screen coordinate system. */
#define X_01(x) \
((double)COXR(x)/(double)(dimX)) \
/* Put a [0,1] value into X-screen coordinate system. */
#define COYR(y) \
((int)((y) - Ymin)) \
/* Relative value of an 'Y' coordinate. */
#define COYA(y) \
((int)((y) + Ymin)) \
/* "Absolute" value of an 'Y' coordinate. */
#define Y_SCREEN(y) \
COYA((int)((double)(y)*((double)dimY))) \
/* Put a [0,1] value into Y-screen coordinate system. */
#define Y_01(y) \
((double)COYR(y)/(double)(dimY)) \
/* Put a [0,1] value into Y-screen coordinate system. */
#define LENG(origine,extremite) \
((int)((extremite)-(origine)+1)) \
/* Compute a length. */
#define MODS(x,origine,extremite) \
(((x) < (origine)) ? \
((x)-(((((x)+1-(origine))/LENG(origine,extremite))-1)*LENG(origine,extremite))) : \
(((x) > (origine)) ? \
((x)-((((x)-(origine))/LENG(origine,extremite))*LENG(origine,extremite))) : \
(x) \
) \
) \
/* Modulo. */
#define Xmodulo(x,period) \
COXA(MODS(COXR(x),COXR(Xmin),X_SCREEN(period))) \
/* Put 'x' inside [Xmin,Xmin+period-1]. */
/*************************************************************************************************************************************/
/* */
/* A U T O S T E R E O G R A M G E N E R A T I O N : */
/* */
/*************************************************************************************************************************************/
Rpicture(unsigned char
,AutostereogramGeneration(Autostereogram,Depth,MultiplicativeFactor,Texture,IntrinsicPeriod,ActualPeriod,TextureSwap)
)
Rpicture(unsigned char,Autostereogram);
/* The autostereogram to be generated. */
Rpicture(double,Depth);
double MultiplicativeFactor;
/* The depth field of the scene to be displayed is defined itself as a picture ; high */
/* values correspond to points that are close to the viewer. */
Rpicture(unsigned char,Texture);
double IntrinsicPeriod;
double ActualPeriod;
/* The 2D texture to be used. Two periods are characteristic : */
/* */
/* 1-IntrinsicPeriod gives the intrinsic period of Texture ; for example, if Autostereogram */
/* should be made of 5 vertical bands, it is equal to 0.2 (=1/5). */
/* */
/* 2-ActualPeriod generally equals IntrinsicPeriod but it could be different in the case */
/* where texture is pseudo-periodical. It gives the width of the used area of Texture. */
int TextureSwap;
/* A logical indicator ; a null value allows the possible swap of texture points during */
/* the left shift process. This allows "dynamical" effects and for example "ghost" subsets */
/* of the 3D object that appear and disappear according to the point of view. */
{
Dpicture(unsigned char,TemporaryTexture);
/* A temporary picture containing the texture during the */
/* process of circular shifting of Texture. */
int X,Y;
for (Y=Ymin ; Y<=Ymax ; Y++)
{
for (X=Xmin ; X<=Xmax ; X++)
{
IMAGE(TemporaryTexture,X,Y) = IMAGE(Texture,X,Y);
/* Copy the whole input texture (could be optimized according */
/* to IntrinsicPeriod and ActualPeriod). */
}
}
for (Y=Ymin ; Y<=Ymax ; Y++)
{
double FormerLeftshift=0;
for (X=Xmin ; X<=Xmax ; X++)
{
double Leftshift=MultiplicativeFactor*IMAGE(Depth,X,Y);
double ActualLeftshift=((TextureSwap==0)||((FormerLeftshift-Leftshift)<=1)) ?
Leftshift :
FormerLeftshift-1;
/* Texture will be left circular shifted proportionally to the */
/* current Depth ; however, the actual left shift depends on */
/* the swapping enabling of the texture. */
int n;
for (n=1 ; n<=(ActualPeriod/IntrinsicPeriod) ; n++)
/* For the sake of simplicity it is assumed that IntrinsicPeriod */
/* divides exactly ActualPeriod. */
{
int Xperiodic=Xmodulo(X+(n-1)*X_SCREEN(IntrinsicPeriod),ActualPeriod);
double Xf=Xperiodic+ActualLeftshift;
int Xfi=(int)Xf;
double Xfd=Xf-(double)Xfi;
IMAGE(TemporaryTexture,Xmodulo(Xperiodic+0,ActualPeriod),Y)
= (1-Xfd)*IMAGE(TemporaryTexture,Xmodulo(Xfi+0,ActualPeriod),Y)+
(Xfd)*IMAGE(TemporaryTexture,Xmodulo(Xperiodic+0,ActualPeriod),Y);
IMAGE(TemporaryTexture,Xmodulo(Xperiodic+1,ActualPeriod),Y)
= (Xfd)*IMAGE(TemporaryTexture,Xmodulo(Xfi+1,ActualPeriod),Y)+
(1-Xfd)*IMAGE(TemporaryTexture,Xmodulo(Xperiodic+1,ActualPeriod),Y);
/* shift the current texture according to the current depth. */
}
IMAGE(Autostereogram,X,Y) = IMAGE(TemporaryTexture,Xmodulo(X,ActualPeriod),Y);
/* Generation of Autostereogram. */
FormerLeftshift = ActualLeftshift;
}
}
return(Autostereogram);
}
/*************************************************************************************************************************************/
/* */
/* T E X T U R E G E N E R A T I O N F R O M A N O B J E C T V I E W : */
/* */
/*************************************************************************************************************************************/
void TextureGenerationFromView(Depth,Texture,DepthOfRealisticView,RealisticView)
Rpicture(double,Depth);
Rpicture(unsigned char,Texture);
/* Depth field and 2D texture to be used to produce the */
/* autostereogram. */
Rpicture(double,DepthOfRealisticView);
Rpicture(unsigned char,RealisticView);
/* The "realistic" view of the object(s) to be displayed. */
{
int X,Y;
for (Y=Ymin ; Y<=Ymax ; Y++)
{
for (X=Xmin ; X<=Xmax ; X++)
{
IMAGE(Depth,X,Y) = ((X>=(Xmin+((Xmax-Xmin)/3))) && (X<(Xmin+((2*(Xmax-Xmin))/3)))) ?
IMAGE(DepthOfRealisticView,X,Y) :
0;
/* The depth field is extracted from the center of the realistic */
/* view and remains center aligned. The left and right bands */
/* are initialized to zero thus giving birth to a background */
/* plane. */
IMAGE(Texture,X,Y) = (X<(Xmin+((Xmax-Xmin)/3))) ?
IMAGE(RealisticView,X+((Xmax-Xmin)/3),Y) :
0;
/* The 2D texture is extracted from the center of the realistic */
/* view and is left aligned. */
}
}
}
/*************************************************************************************************************************************/
/* */
/* M A I N T E S T P R O G R A M : */
/* */
/*************************************************************************************************************************************/
extern double exp();
extern double sin();
extern double drand48();
#define BLACK 0
#define WHITE 255
#define GreyLevel(n) \
((unsigned char)(BLACK + ((n)*(WHITE-BLACK))))
#define fGreyLevel(n) \
((BLACK + ((n)*(WHITE-BLACK))))
/* Convert a [-1,+1] value into a grey level. */
int main()
{
Get(dimX,"dimX");
Get(dimY,"dimY");
/* Get the definition of the picture size : */
/* */
/* setenv dimX ... */
/* setenv dimY ... */
/* */
{
Dpicture(unsigned char,Autostereogram);
/* The autostereogram to be generated. */
Dpicture(unsigned char,RealisticView);
Dpicture(double,DepthOfRealisticView);
int DepthChoice;
Dpicture(double,Depth);
double MultiplicativeFactor;
/* The depth field of the scene to be displayed is defined itself as a picture ; high */
/* values correspond to points that are close to the viewer. */
int TextureChoice;
Dpicture(unsigned char,Texture);
double IntrinsicPeriod;
double ActualPeriod;
/* The 2D texture to be used. Two periods are characteristic : */
/* */
/* 1-IntrinsicPeriod gives the intrinsic period of Texture ; for example, if Autostereogram */
/* should be made of 5 vertical bands, it is equal to 0.2 (=1/5). */
/* */
/* 2-ActualPeriod generally equals IntrinsicPeriod but it could be different in the case */
/* where texture is pseudo-periodical. It gives the width of the used area of Texture. */
int TextureSwap;
/* A logical indicator ; a null value allows the possible swap of texture points during */
/* the left shift process. This allows "dynamical" effects and for example "ghost" subsets */
/* subsets of the 3D object that appear and disappear according to the point of view. */
DepthChoice=1;
/* Definition : */
/* */
/* 0 : sinusoidal, */
/* 1 : gaussian. */
/* */
TextureChoice=0;
/* Definition : */
/* */
/* 0 : random, */
/* 1 : vertical lines, */
/* 2 : color bars. */
/* */
int X,Y;
for (Y=Ymin ; Y<=Ymax ; Y++)
{
for (X=Xmin ; X<=Xmax ; X++)
{
switch (TextureChoice)
{
case 0:
{
IMAGE(Texture,X,Y) = GreyLevel(drand48());
/* Computation of a random texture... */
break;
}
case 1:
{
IMAGE(Texture,X,Y) = GreyLevel(((X%(dimX/10))<=((dimX/100)-1)) ? 1 : 0);
/* Computation of vertical lines (introduced on 20110603132430). */
break;
}
case 2:
{
IMAGE(Texture,X,Y) = MODS((X*((dimX/100)-1)),BLACK,WHITE);
/* Computation of vertical color bars (introduced on 20110605092911). */
break;
}
default:
{
IMAGE(Texture,X,Y) = GreyLevel(0);
break;
}
}
switch (DepthChoice)
{
case 0:
{
IMAGE(Depth,X,Y) = fGreyLevel((1+sin(4*3.1415*X_01(X)))/2);
/* Computation of a sinusoidal depth field. */
break;
}
case 1:
{
IMAGE(Depth,X,Y) = fGreyLevel(exp(-10*(((X_01(X)-0.5)*(X_01(X)-0.5))+
((Y_01(Y)-0.5)*(Y_01(Y)-0.5))
)
)
);
/* Computation of a gaussian depth field (introduced on 20110603132430). */
break;
}
default:
{
IMAGE(Depth,X,Y) = fGreyLevel(0);
break;
}
}
if (0)
/* Test sequence for the function 'TextureGenerationFromView(...)', not needed here... */
{
IMAGE(RealisticView,X,Y) = IMAGE(Depth,X,Y);
IMAGE(DepthOfRealisticView,X,Y) = IMAGE(Depth,X,Y);
}
else
{
}
}
}
MultiplicativeFactor = 0.24;
IntrinsicPeriod = 0.2;
ActualPeriod = 0.2;
TextureSwap = 1;
AutostereogramGeneration(Autostereogram
,Depth,MultiplicativeFactor
,Texture,IntrinsicPeriod,ActualPeriod,TextureSwap
);
/* Computation of the random autostereogram. */
if (0)
/* Test sequence for the function 'TextureGenerationFromView(...)', not needed here... */
{
TextureGenerationFromView(Depth,Texture,DepthOfRealisticView,RealisticView);
AutostereogramGeneration(Autostereogram
,Depth,MultiplicativeFactor
,Texture,IntrinsicPeriod,ActualPeriod,TextureSwap
);
}
else
{
}
write(1,Autostereogram,dimX*dimY);
/* Acces to the generated autostereogram is given on 'Stdout'. */
}
return(0);
}