# 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](3d.md) structure within it by [cheating](cheating.md) human stereoscopic vision (it is therefore in a sense also an optical illusion). As the name suggests it is a special case of [stereogram](stereogram.md) 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](autostereoscopy.md) or [holography](holograph.md) -- 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](interesting.md) type of autostereogram -- one whose creation can easily be automatized with a program and which lets us embed any depth image (or *[heightmap](heightmap.md)*) 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](ascii_art.md) as compared to a true bitmap image.* The following is a [C](c.md) 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; } ```