Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Last active December 26, 2015 18:09
Embed
What would you like to do?
magic
-- MagicEye
--by ignatz
--taken from http://www.techmind.org/stereo/stech.html
--[[
This code creates "magic eye", or stereoscopic pictures. If you focus beyond the picture, you should
be able to see a hidden image. The technical details, and the code I used to make this, are here:
http://www.techmind.org/stereo/stech.html
This is how the result of this code looks (but DON'T run it before reading all these notes)
https://www.dropbox.com/s/fa9lo9p97t9057k/magic.JPG
The code below creates a sterogram from an outline image plus a pattern image. If you want to make a picture with
several images in it, use setContext and sprite each image onto a combined image which you can then use with
the code below.
The outline image is just the outline of a picture, ideally something that is easy to recognise, like a shark, or mickey mouse. The whole outline is filled with a single colour that will tell the program how far away to put the image, inside the stereogram, so a colour of 127 will be about halfway to the back, and 200 will be close to the back.
The pattern image is the pattern the viewer will see at first. It needs to be quite noisy so that the stereogram stands out clearly.
NOTE: The code will not run as it is because you don't have the outline or pattern images it is asking for. You will need to put in your own images. Or you can download and save the images used in the code from here
Outline - https://www.dropbox.com/s/2o33v91rd0hmz58/shark.png
Pattern - https://www.dropbox.com/s/kxlz65ofy7ynq0j/3D-water1.png
The code consists of two parts
1. CreateDepthOutline - which takes an ordinary image, and creates an outline of it (make sure the pixels around the image are transparent or you'll just get a rectangle!), at the depth you want. It uses a "shader" (the code at
the very bottom).
There are three parameters
* the original image
* the depth you want to show the image (0-1, 0=up close, 1=background)
* the scale - eg 2 will double the size of your image, 0.5 will halve its size
2. CreateStereogram - this creates the stereogram. It returns the final image
There are two parameters
* the pattern image
* the outline image
--]]
function setup()
--load the image to go into the picture
a=readImage("Dropbox:shark") --this is what we will see
--create an outline version, 80% of the way to the background, double the size
b=CreateDepthOutline(a,.8,2)
img1=readImage("Dropbox:3D-water1") --the pattern image
img=CreateStereogram(img1,b) --creaet the stereogram
end
function draw()
background(40, 40, 50)
sprite(img,WIDTH/2,HEIGHT/2)
end
function CreateStereogram(imgPat,imgDepth)
img2=image(imgDepth.width,imgDepth.height)
patHeight=imgPat.height
maxwidth=imgDepth.width*6 -- allow space for up to 6 times oversampling
xdpi=75
ydpi=75
yShift=ydpi/16
width=imgDepth.width
height=imgDepth.height
oversam=4 -- oversampling ratio
lookL,lookR={},{}
colour={}
lastlinked=0
vwidth=width*oversam
obsDist=xdpi*12
eyeSep=xdpi*2.5
veyeSep=math.floor(eyeSep*oversam+0.5)
maxdepth=xdpi*12
maxsep=math.floor((eyeSep*maxdepth)/(maxdepth+obsDist)+0.5)-- pattern must be at least this wide
vmaxsep=oversam*maxsep
s=vwidth/2-vmaxsep/2
poffset=vmaxsep-math.fmod(s,vmaxsep)
featureZ, sep=0,0
x,y,left,right=0,0,0,0
vis=false
print("obs dist",obsDist)
print("maxsep",maxsep)
print("mindepth",(0.55*maxdepth*obsDist)/((1-.55)*maxdepth+obsDist))
for y=height-1,0,-1 do
for x=0,vwidth-1 do
lookL[x]=x
lookR[x]=x
end
for x=0,vwidth-1 do
if math.fmod(x,oversam)==0 then -- SPEEDUP for oversampled pictures
local x=math.floor(x/oversam+0.5)
featureZ=imgDepth:get(x+1,y+1)*obsDist/255 ---[2]
-- DEPTH stored in red pixel
sep=math.floor((veyeSep*featureZ)/(featureZ+obsDist)+0.5)
end
left=math.floor(x-sep/2+0.5)
right=left+sep
vis=true
if left>=0 and right<vwidth then
if lookL[right]~=right then -- right pt already linked
if lookL[right]<left then -- deeper than current
lookR[lookL[right]]=lookL[right] -- break old links
lookL[right]=right
else vis=false
end
--else vis=false
end
if lookR[left]~=left then -- left pt already linked
if lookR[left]>right then -- deeper than current
lookL[lookR[left]]=lookR[left] --break old links
lookR[left]=left
else vis=false
end
--else vis=false
end
if vis==true then
lookL[right]=left
lookR[left]=right -- make link
end
end
end
lastlinked=-10 -- dummy initial value
for x=s,vwidth-1 do
if lookL[x]==x or lookL[x]<s then
if lastlinked==x-1 then
colour[x]=colour[x-1]
else
local xx=math.fmod(x+poffset,vmaxsep)/oversam+1
local yy=math.fmod(y+(x-s)/vmaxsep*yShift,patHeight)+1
local r,g,b=imgPat:get(xx,yy)
colour[x]=color(r,g,b)
end
else
colour[x]=colour[lookL[x]]
lastlinked=x -- keep track of the last pixel to be constrained
end
end
lastlinked=-10 -- dummy initial value
for x=s-1,0,-1 do
if lookR[x]==x then
if lastlinked==x+1 then
colour[x]=colour[x+1]
else
local xx=math.fmod(x+poffset,vmaxsep)/oversam+1
local yy=math.fmod(y+((s-x)/vmaxsep+1)*yShift,patHeight)+1
local r,g,b=imgPat:get(xx,yy)
colour[x]=color(r,g,b)
end
else
colour[x]=colour[lookR[x]]
lastlinked=x -- keep track of the last pixel to be constrained
end
end
for x=0,vwidth-1,oversam do
red,green,blue=0,0,0
-- use average colour of virtual pixels for screen pixel
for i=x,x+oversam-1 do
red=red+colour[i].r
green=green+colour[i].g
blue=blue+colour[i].b
end
col=color(red/oversam, green/oversam, blue/oversam)
img2:set(math.floor(x/oversam+1.5),y+1, col)
end
end
return img2
end
function CreateDepthOutline(img,d,s) --d is fraction 0-1, s is scale (1=normal)
s=s or 1
local w,h=img.width*s,img.height*s
local m=mesh()
m:addRect(w/2,h/2,w,h)
m.texture=img
m:setColors(color(d*255))
m.shader=shader(outlineShader.vertexShader,outlineShader.fragmentShader)
local img2=image(w,h)
setContext(img2)
m:draw()
setContext()
return img2
end
outlineShader = {
vertexShader = [[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
vColor=color;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
lowp vec4 col = texture2D( texture, vTexCoord ) ;
if (col.a > 0.0) gl_FragColor = vColor;
else gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}
]]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment