Last active
December 26, 2015 18:09
-
-
Save dermotbalson/7192218 to your computer and use it in GitHub Desktop.
magic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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