Random Dot Stereograms

Authors

Publication

Pub Details

Date

Pages

See all articles from QL Hacker's Journal 9

Random Dot Stereograms (RDS) can give the illusion of depth if you have binocular vision. Instead of the usual pair of stereoscopic pictures, a single ‘picture’ is made with several swaths side by side, interleaved so as to provide the brain with depth clues when you gaze at the dots in a certain way. It takes a little blinking and practice, but when it ‘snaps-in’ to view the effect is marvelous. Once seen, it is fairly easy to find again.

The best width for a swath is about half the distance between your eyes, say an inch or so. I have been using seven swaths, so that a RDS can be made on the screen that is about 7 inches wide and 6 inches high, and the effect is pleasing. I’ve done two so far, one a ‘splash’ like ripples in a pond and another of a pretzel. I’ve enjoyed working out the procedures and functions in SuperBasic, and a RDS only takes a minute or so to develop. Maybe I’ll get (or take) the time to try it in C to speed things up, or even do animation in 3D!

I’ve tried other swath widths, dot sizes, dot densities, and dot quantities, so you can too! A dot size of 1 pixel used to now and then ‘hang’ the QL into limbo, but since I added a missing END IF it has been OK. Pixels of size 4 are pretty good, and faster. A density of 1% or even less will work! The minimum number of dots per swath seems to be around 42 or so.

There is a short program “eyefuse3” to calibrate your setup for the range of separation that you can accomodate. See how close and how far you can still fuse two images into three, and then pick a middle value for your swath width.

Simple objects like a sphere are probably easier to find for the beginner, but splashes, pretzles, and saddles, etc. are fun. Some simpler DEFine FuNctions are included. Enjoy!

eyefuse3

100 REMark eyefuse3
125 WTV
126 PAPER 4 :INK 0
127 CLS
135 xo = 50: yo = 50
137 sep = 100
145 n = 8
155 bk = 1
165 explain
175 PAPER 0 : INK 6
180 CLS
200 FOR ac = 1 TO n
210 FOR dn = 1 TO n
220 BLOCK bk*1.5,bk,xo+ac*bk*1.5,yo+dn*bk,
((ac MOD 2 + dn MOD 2) MOD 2)*4
222 BLOCK bk*1.5,bk,100+xo+ac*bk*1.5,yo+dn*bk,
((((ac MOD 2 + dn MOD 2) MOD 2)-1)*-1)*2
230 END FOR dn
240 END FOR ac
247 CURSOR xo+n*1.5,yo :PRINT;"o"
248 CURSOR sep+xo+n*1.5,yo :PRINT;"O"
249 AT 16,2:PRINT;"use <--ク and ケ--> keys"
250 AT 17,2:PRINT;" to change separation"
251 AT 19,2:PRINT " hold ESC key to exit"
255 REPeat moves
257 AT 10,15: PRINT;sep;" "
258 CURSOR xo+sep , yo
260 IF INKEY$(-1) = CHR$(192) : PAN -1,4 :sep=sep-1
270 IF INKEY$(-1) = CHR$(200) : PAN 1,4 :sep=sep+1
280 IF INKEY$(-1) == CHR$(27) : EXIT moves
290 END REPeat moves
300 DEFine PROCedure explain
310 PRINT " If you have
binocular vision and can see fairly well"¥
320 PRINT "with either eye, it is possible that you may be
able"¥
330 PRINT "to 'see' objects in depth on your QL monitor
screen"¥¥
340 PRINT "This exercise will 'calibrate' your eyes and your
VDU"¥
350 PRINT¥"Make a note of the separation distance in pixels
when"¥
360 PRINT "you find it easiest to fuse the two little
checker boards"
365 PRINT "into THREE little checkerboards."
370 PRINT "If you see 3 that's great; If you see two or
four, change"¥
380 PRINT "something: tilt your head, blink, move away from
or closer"¥
390 PRINT "to the screen, change eye-glasses, etc. while
trying the"¥
400 PRINT "various pixel separations"¥
410 PRINT "The big 'O' will dominate the little 'o' when you
have"¥
420 PRINT "good super-imposition and the center checkerboard
will"¥
425 PRINT "be olive-drab"¥¥"Touch [SPACE BAR] to continue"
435 PAUSE
445 END DEFine explain
455 REMark end of eyefuse3

RDSphere_QLHJ_bas

100 REMark   RDSphere_QLHJ_bas
110 REMark H.L Schaaf May 9,1992
120 REMark ref. Mathematica Journal Winter 1991 V.1,N.3,
p.69-75
130 REMark 'Random Dot Stereograms' by Dror Bar-Natan @
Princeton
140 REMark dror@math.princeton.edu
150 ipl_dis = -20 :REMark image plane displacement, +
is closer
160 obj_dis = 10 :REMark object displacement, - is more
distant
170 iwide =360 : ihigh =240 : REMark image width and
height
180 ytox = 4/3 : REMark y to x aspect ratio of QL blocks
190 swide = 60 : REMark swath width
200 zscale = 8 : REMark adjust for depth of Z axis
210 MODE 4 : CSIZE#2,1,0:CSIZE#0,0,0
220 WINDOW#1, iwide+8,256,0,0 :PAPER 0 : INK 7
230 WINDOW#2,144,190,368,0 : BORDER#2,2,2
240 PAPER#2,4 : INK #2,0
250 WINDOW#0 ,144,64,368,192 :BORDER #0,2,4
260 nk = 7 : REMark ink color 7 = white
270 CLS#0 : CLS#2 : CLS#1
280 REMark fill in with blocks
290 :
300 REMark ask for density and block size
310 INPUT#2; " % density ? ";dens : density = dens/100
320 INPUT #2;"Block size ? ";bk
330 hb = bk/2 : REMark half block
340 :
350 d_begin = DATE : REMark start timer
360 :
370 ac = swide DIV bk : REMark blocks across (columns)
380 ns = 2*ac : REMark allow for left shifts
390 dn = ihigh DIV bk : REMark blocks down (rows)
395 :
400 REMark create random pattern for first swath
404 RANDOMISE(32000)
410 DIM rdot%(density*ac*dn)
415 cnt = DIMN(rdot%)
417 FOR i = 0 TO cnt
418 rdot%(i) = RND (0 TO ac*dn)
419 END FOR i
420 :
580 REMark recap
590 PRINT#2¥¥" "; :UNDER#2, 1
600 PRINT#2;"Swath Data:" : UNDER#2, 0
610 PRINT#2;" ";ac;" across"
620 PRINT#2;" ";dn;" down"
630 PRINT#2;" ";ac*dn;" total"
640 PRINT #2;" ";cnt;" dots/swath"
650 PRINT #2;" ";(INT(10000*cnt/(ac*dn)))/100;" %
density"
660 :
670 REMark create swaths
680 DIM swaths%(cnt,ns)
690 :
700 REMark put random pattern into first swath
710 REMark y values go into zeroth elements
720 FOR count = 0 TO cnt
730 i = rdot%(count) DIV (ac)
740 j = rdot%(count) - i*(ac)
750 swaths%(count,0)=i*bk
760 swaths%(count,1)=j*bk
765 BLOCK bk,bk,swaths%(count,1),swaths%(count
,0),nk
770 END FOR count
780 :
790 REMark create guides to help get proper 'focus'
800 gdlx=(iwide-swide)/2 : gdly=ihigh+6
810 gdrx=(iwide+swide)/2 : gdry=gdly
820 BLOCK 8,8,gdlx,gdly,nk
830 BLOCK 4,4,gdlx+2,gdly+2,0
840 BLOCK 8,8,gdrx,gdry,nk
850 BLOCK 4,4,gdrx+2,gdry+2,0
860 :
870 REMark geometric reference coordinates
880 xcntr=(iwide-swide)/2 : ycntr = ihigh/2
890 :
900 REMark a function to return the 3D value
910 DEFine FuNction sphere(x,y)
920 LOCal xs,ys,xx,yy
930 radius = 8*8
940 diam = 2*radius
950 diamsq = diam*diam
960 xs=ABS(xcntr-(x+hb))
970 ys=ABS(ycntr-(y+hb))*ytox
980 xy = (xs*xs+ys*ys)
990 IF xy > diamsq
1000 offset = ipl_dis
1010 ELSE
1020 zz = diamsq-xy
1030 z=SQRT(zz)
1040 offset = z + obj_dis
1050 END IF
1060 RETurn offset DIV zscale
1070 END DEFine
1080 :
1090 REMark build remaining swaths
1100 OVER 1
1110 FOR i = 0 TO cnt
1120 FOR j = 2 TO ns
1130 ZD = sphere(swaths%(i,j-1),swaths%(i,0))
1140 swaths%(i,j)=swide+(swaths%(i,j-1)) - ZD
1150 IF ((swaths%(i,j)+bk)>iwide) : EXIT j
1160 BLOCK bk,bk,swaths%(i,j),swaths%(i,0),nk
1170 END FOR j
1180 END FOR i
1190 :
1200 d_end = DATE :REMark stop timer
1210 d_lap = d_end - d_begin
1220 PRINT #2¥¥" Elapsed time:"¥" ";d_lap;" seconds"
1230 :
1240 REMark save screen
1250 SBYTES_O ram2_rds_scr,2^17,2^15
1260 PRINT #2¥¥" sbytes saved to"¥" ram2_rds_scr"
1270 :
1280 STOP

Following are some other DEFine Functions: (Change line 1130 to suit)

A Pyramid of sorts

900 REMark a function to return the 3D value
910 DEFine FuNction pyr(x,y)
920 LOCal xs,ys,xx,yy
930 baseline = 150
960 xs=ABS(xcntr-(x+hb))
970 ys=ABS(ycntr-(y+hb))*ytox
980 xy = (xs+ys)
990 IF xy > baseline
1000 offset = ipl_dis
1010 ELSE
1020 zz = baseline-xy
1040 offset = zz + obj_dis
1050 END IF
1060 RETurn offset DIV zscale
1070 END DEFine

Imagine a Phillips head cavity ?

900 REMark a function to return the 3D value
910 DEFine FuNction phlhd(x,y)
920 LOCal xs,ys,xx,yy
930 baseline = 80
960 xs=ABS(xcntr-(x+hb))
970 ys=ABS(ycntr-(y+hb))*ytox
980 xy = SQRT(xs*ys)
990 IF xy > baseline
1000 offset = ipl_dis
1010 ELSE 1020 zz = xy - baseline
1040 offset = zz + obj_dis
1050 END IF
1060 RETurn offset DIV zscale
1070 END DEFine

Fan-blades making an X?

900 REMark a function to return the 3D value
910 DEFine FuNction xvane(x,y)
920 LOCal xs,ys,xx,yy
930 baseline = 50
960 xs=ABS(xcntr-(x+hb))
970 ys=ABS(ycntr-(y+hb))*ytox
980 xy = (xs-ys)
990 IF ABS(xy) > baseline
1000 offset = ipl_dis
1010 ELSE
1020 zz = baseline - xy
1040 offset = zz + obj_dis
1050 END IF
1060 RETurn offset DIV zscale
1070 END DEFine

Diamond shape (similar to pyramid)

900 REMark a function to return the 3D value
910 DEFine FuNction diamond(x,y)
920 LOCal xs,ys,xx,yy
930 baseline = 100
960 xs=ABS(xcntr-(x+hb))
970 ys=ABS(ycntr-(y+hb))*ytox
980 xy = (2*xs+3*ys)/5
990 IF xy > baseline
1000 offset = ipl_dis
1010 ELSE
1020 zz = baseline - xy
1040 offset = zz + obj_dis
1050 END IF
1060 RETurn offset DIV zscale
1070 END DEFine

Sinc – the classic splash, change scales for sombrero

900 REMark a function to return the 3D value
910 DEFine FuNction sinc(x,y)
920 LOCal xs,ys,xx,yy
960 xs=ABS(xcntr-(x+hb))/swide
970 ys=ABS(ycntr-(y+hb))*ytox/swide
980 xy = SQRT(xs*xs+ys*ys)/2
1020 z = 2*PI*xy
1040 offset = 2*swide*(SIN(z)/z)
1050 END IF
1060 RETurn offset DIV zscale
1070 END DEFine

P.S. I’m especially proud of my ‘pretzle’ sometimes known as the Escher knot. If there is interest let the Editor know, and we will show you the complicated way I did it. Even better, show us your interesting RDS FuNctions etc.!

Products

 

Downloadable Media

 
Scroll to Top