7.5 KiB
Autostereogram
Autostereogram is a cool sort of image that when viewed in a special way (with eyes crossed or "walled") enables the viewer to see a 3D structure within it by cheating human stereoscopic vision (it is therefore in a sense also an optical illusion). As the name suggests it is a special case of stereogram but unlike many traditional stereograms consisting of two side by side images, autostereogram is only a single image that forms the perceivable 3D pattern by being overlaid with itself (hence the prefix auto). These images are quite awesome for they implement stereoscopic 3D images without the need for special glasses or complex techniques like autostereoscopy or holography -- autostereograms can be made as long as we can draw plain 2D images, but of course they also suffer from some limitations. There are several types of autostereograms.
Viewing autostereograms is easy for some and difficult for others but don't worry, it can be trained. One trick that's used (for the "cross eyed" types of images) is putting a finger in front of the image, focusing your sight on it and then lowering the finger while keeping your eyes looking at the point where the finger was (for "walled" images you have to be looking beyond the image, i.e. try looking at a wall behind it). Also be careful about the possibility of crossing your eyes "too much" and seeing the image in incorrect way. Once you see the pattern, keep looking at it for a longer time, it becomes clearer and clear as the brain makes out more of the structure (it may also help to slightly move your head from side to side).
TODO
Random Dot Autostereograms
The "random dot" technique gives rise to an especially interesting type of autostereogram -- one whose creation can easily be automatized with a program and which lets us embed any depth image (or heightmap) into an image that consists of some repeating base pattern. And yes, it can even be animated! The pattern image may in theory be anything, even a photo, but it should have great variety, high frequencies and big contrast to work properly, so the typical pattern is just randomly generated color dots. This pattern is then horizontally deformed according to the embedded depth image. A disadvantage is, of course, that we can only embed the depth image, we cannot give it any texture.
TODO: more detail
.:,oX#r-'/=*miQ .:,oX#r-'/=*miQ .:,oX#r-'/=*miQ .:,oX#r-'/=*miQ .:,oX#r-'/=*miQ .:,oX#r-'/=*miQ
miQ)35;_0p]w@x4EmiQ)35;_0p]w@x4EmiQ)35;_0p]w@x4EmiQ)35;_0p]w@x4EmiQ)35;_0p]w@x4EmiQ)35;_0p]w@x4E
x4EY!{ .:,oX#r-'x4EY!{ .:,oX#r-'x4EY!{ .:,oX#r-'x4EY!{ .:,oX#r-'x4EY!{ .:,oX#r-'x4EY!{ .:,oX#r-'
r-'/=*miQ)35;_0pr'/=*miQ)35;_00pr'/=*miQ)35;_00pr'/=*miQ)35;_00pr'/=*miQ)35;_00pr'/=*miQ)35;_00p
_0p]w@x4EY!{ .:,_0]w@x4EY!{ ..:,_0]w@x4EY!..:,_0]w@x4EY!..:.:,_0]w@x4EY!..:.:,_0]w@x4EY!..:.:,_0
.:,oX#r-'/=*miQ).:,o#r-'/=**miQ).:,o#r-'/=*iQ).:,o#r-'/=*iQ).).:,o#r-'/=*iQ.).:,o#r-''/=*iQ).).:
iQ)35;_0p]w@x4EYiQ)3;_0p]w@@x4EYiQ)3;_0p]w@@EYiQ)3;3;_0w@@EYiQiQ)3;3;_0w@EYiQiQ)3;3;_0w@@EYYiQiQ
4EY!{ .:,oX#r-'/4EY! .:,oX##r-'/4EY! .:,oX##'/4EY! ! .:,##'/4E4EY! ! .,##'/4E44EY! .,##''//4E4E
-'/=*miQ)35;_0p]-'/=miQ)35;;_0p]-'/=miQ)35;;p]-'/=m=miQ);;p]-'-'/=m=mi);;p]-''-'/=m=i);;p]]]-'-'
0p]w@x4EY!{ .:,o0p]wx4EY!{ .:,o0p]wx4EY!{ ,o0p]wxwx4!{ ,o0o0p]wxwx4{ ,o0o00p]wxwx4{ ,oo0o0p
:,oX#r-'/=*miQ)3:,oXr-'/=*mmiQ)3:,oXr-'/=*mm)3:,oXr-'/=*mm)3)3:,oXr-'/=*m)3)3:,oXr-''/=*m)33)3:,
Q)35;_0p]w@x4EY!Q)35_0p]w@xx4EY!Q)350pp]w@xxY!Q)350pp]w@xxY!Y!Q)350pp]w@xxY!!Q)350pp]w@xxxY!Y!Q)
EY!{ .:,oX#r-'/=EY!{.:,oX#rr-'/=EY!{:,,oX#rr/=EY!{:{:,,#rr/=E=EY!{:{:,,#rr/=E=EY{:{:,,#rrr/=E=EY
'/=*miQ)35;_0p]w'/=*iQ)35;__0p]w'/*iQ))35;__]w'/*iQiQ))3__]w'/'/*iQi))3__]ww'/'/*ii))3__]www'/'/
p]w@x4EY!{ .:,oXp]wx4EY!{ .:,oXp]wx4EYY!{ .:Xpp]x4E4EYY!{:Xpp]]]x4E4YY!{:Xppp]]]x4EYY!{:Xpppp]]]
,oX#r-'/=*miQ)35,o#r-'/=*miQ)35,o#r-'//=*miQ5,,or-'/'//=*Q5,,oo#r-'/'/=*Q5,,ooo#r-/'/=*Q5,,,,oo#
)35;_0p]w@x4EY!{)35;_0p]w@x4EY!{)35;_0p]w@xY!{)35;_0p0p]wY!{)3)3_;_0p0]wY!{)3)35;_0p0]wY!!{{)3)3
Y!{ .:,oX#r-'/=*Y!{ .:,oX#r-'/=*Y!{ .:,oX#r-'/=*Y!{ .:,oX#r-'/=*Y!{ .:,oXr-'/=*Y!{ .:,,oXr--'/=*
/=*miQ)35;_0p]w@/=*miQ)35;_0p]w@/=*miQ)35;_0p]w@/=*miQ)35;_0p]w@/=*miQ)35;_0p]w@/=*miQ)35;_0p]w@
]w@x4EY!{ .:,oX#]w@x4EY!{ .:,oX#]w@x4EY!{ .:,oX#]w@x4EY!{ .:,oX#]w@x4EY!{ .:,oX#]w@x4EY!{ .:,oX#
If you look at this image the correct way, you'll see a 3D image of big letters spelling out LRS. Please forgive an increased viewing difficulty of ASCII art as compared to a true bitmap image.
The following is a C program that generates the above image.
#include <stdio.h>
#define PATTERN_SIZE 16
#define RES_X 75
#define RES_Y 20
#define PATTERN_SEED_SIZE 32
char patternSeed[PATTERN_SEED_SIZE] = " .:,oX#r-'/=*miQ)35;_0p]w@x4EY!{";
char depth[RES_X * RES_Y + 1] = // must be big and simple to be easily seen
" "
" "
" "
" 1111111111111 "
" 11111111111 22222222222222222 "
" 1111111 222222222222222222 1111111111 "
" 1111111 2222222 2222222 1111111111111111 "
" 1111111 2222222 222222 11111111 111111 "
" 1111111 2222222 222222 1111111 111111 "
" 1111111 2222222 2222222 11111111 "
" 1111111 2222222222222222 111111111111 "
" 1111111 11 2222222222222222 111111111111 "
" 1111111 11 2222222 222222 111111111 "
" 1111111 1111 2222222 222222 1111111 11111111 "
" 1111111111111111111 2222222 222222 1111111 1111111 "
" 11111111111111111111 22222222 2222222 11111111 11111111 "
" 2222222222 22222222 1111111111111111111 "
" 1111111111111 "
" "
" ";
char buffer1[PATTERN_SIZE + 1];
char buffer2[PATTERN_SIZE + 1];
int charToDepth(char c)
{
return c == ' ' ? 0 : (c - '0');
}
int main(void)
{
const char *c = depth;
char *lineCurrent, *linePrev;
buffer1[PATTERN_SIZE] = 0;
buffer2[PATTERN_SIZE] = 0;
for (int j = 0; j < RES_Y; ++j)
{
for (int i = 0; i < PATTERN_SIZE; ++i) // initiate first pattern from seed
buffer1[i] = patternSeed[(i + (j * 13)) % PATTERN_SEED_SIZE];
lineCurrent = buffer1;
linePrev = buffer2;
for (int i = 0; i < RES_X; ++i)
{
if (i % PATTERN_SIZE == 0)
{
printf("%s",lineCurrent); // print the rendered line
char *tmp = lineCurrent; // swap previous and current buffer
lineCurrent = linePrev;
linePrev = tmp;
}
lineCurrent[i % PATTERN_SIZE] = // draw the offset pixel
linePrev[(PATTERN_SIZE + i + charToDepth(*c)) % PATTERN_SIZE];
c++;
}
printf("%s\n",lineCurrent); // print also the last buffer
}
return 0;
}