Skip to content

Commit f5d829b

Browse files
authored
Add files via upload
1 parent 56f5594 commit f5d829b

27 files changed

+87063
-0
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Teensy3.1_Eyes
2+
3+
'Uncanny eyes' project for PJRC Teensy 3.1 with Adafruit 1.5" OLED (product #1431) or 1.44" TFT LCD (#2088). This uses Teensy-3.1-specific features and WILL NOT work on normal Arduino or other boards! Use 72 MHz (Optimized) board speed -- OLED does not work at 96 MHz.
4+
5+
How-to guide with parts list and 3D models is here:
6+
https://learn.adafruit.com/animated-electronic-eyes-using-teensy-3-1/overview
7+
8+
Directory 'uncannyEyes' contains Arduino sketch for PJRC Teensy 3.1. 'uncannyEyes.ino' is the code, 'eyeData.h' is a set of arrays containing eye bitmaps, etc.
9+
10+
Folder 'convert' contains Python sketch for generating eyeData.h. Requires Python Imaging Library. Example images are also in this directory.

convert/defaultEye.h

+16,050
Large diffs are not rendered by default.

convert/defaultEye/iris.png

30.5 KB
Loading

convert/defaultEye/lower.png

1.32 KB
Loading

convert/defaultEye/sclera.png

45 KB
Loading

convert/defaultEye/upper.png

1.86 KB
Loading

convert/dragonEye/dragonPupilMap.png

3.11 KB
Loading

convert/dragonEye/iris.png

71.3 KB
Loading

convert/dragonEye/lower.png

1.4 KB
Loading

convert/dragonEye/sclera.png

82 Bytes
Loading

convert/dragonEye/upper.png

2.16 KB
Loading

convert/goatEye/goatPupilMap.png

3.07 KB
Loading

convert/goatEye/iris.png

18.3 KB
Loading

convert/goatEye/lower.png

1.66 KB
Loading

convert/goatEye/sclera.png

81 Bytes
Loading

convert/goatEye/upper.png

2.1 KB
Loading

convert/noScleraEye.h

+15,637
Large diffs are not rendered by default.

convert/noScleraEye/iris.png

72.1 KB
Loading

convert/noScleraEye/lower.png

1.4 KB
Loading

convert/noScleraEye/sclera.png

82 Bytes
Loading

convert/noScleraEye/upper.png

2.16 KB
Loading

convert/tablegen.py

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
#!/usr/bin/python
2+
3+
# Image converter for 'Uncanny Eyes' project. Generates tables for
4+
# eyeData.h file. Requires Python Imaging Library. Expects four image
5+
# files: sclera, iris, upper lid map and lower lid map (defaults will be
6+
# used if not specified). Also generates polar coordinate map for iris
7+
# rendering (pass diameter -- must be an even value -- as 5th argument).
8+
# Output is to stdout; should be redirected to file for use.
9+
10+
# This is kinda some horrible copy-and-paste code right now for each of
11+
# the four images...could be improved, but basically does the thing.
12+
13+
import sys
14+
import math
15+
from PIL import Image
16+
17+
columns = 8 # Number of columns in formatted output
18+
19+
# Write hex digit (with some formatting for C array) to stdout
20+
def outputHex(n, digits):
21+
global columns, column, counter, limit
22+
column += 1 # Increment column number
23+
if column >= columns: # If max column exceeded...
24+
sys.stdout.write("\n ") # end current line, start new one
25+
column = 0 # Reset column number
26+
sys.stdout.write("{0:#0{1}X}".format(n, digits + 2))
27+
counter += 1 # Increment element index
28+
if counter < limit: # If NOT last element in list...
29+
sys.stdout.write(",") # add column between elements
30+
if column < (columns - 1): # and space if not last column
31+
sys.stdout.write(" ")
32+
else:
33+
print(" };"); # Cap off table
34+
35+
36+
# OPEN AND VALIDATE SCLERA IMAGE FILE --------------------------------------
37+
38+
try: filename = sys.argv[1]
39+
except: filename = "sclera.png"
40+
im = Image.open(filename)
41+
im = im.convert("RGB")
42+
pixels = im.load()
43+
44+
# GENERATE SCLERA ARRAY ----------------------------------------------------
45+
46+
# Initialize outputHex() global counters:
47+
counter = 0 # Index of next element to generate
48+
column = columns # Current column number in output
49+
limit = im.size[0] * im.size[1] # Total # of elements in generated list
50+
51+
print "#define SCLERA_WIDTH" + str(im.size[0])
52+
print "#define SCLERA_HEIGHT" + str(im.size[1])
53+
print
54+
55+
sys.stdout.write("const uint16_t sclera[SCLERA_HEIGHT][SCLERA_WIDTH] = {")
56+
57+
# Convert 24-bit image to 16 bits:
58+
for y in range(im.size[1]):
59+
for x in range(im.size[0]):
60+
p = pixels[x, y] # Pixel data (tuple)
61+
outputHex(((p[0] & 0b11111000) << 8) | # Convert 24-bit RGB
62+
((p[1] & 0b11111100) << 3) | # to 16-bit value w/
63+
( p[2] >> 3), 4) # 5/6/5-bit packing
64+
65+
66+
# OPEN AND VALIDATE IRIS IMAGE FILE ----------------------------------------
67+
68+
try: filename = sys.argv[2]
69+
except: filename = "iris.png"
70+
im = Image.open(filename)
71+
if (im.size[0] > 512) or (im.size[1] > 128):
72+
sys.stderr.write("Image can't exceed 512 pixels wide or 128 pixels tall")
73+
exit(1)
74+
im = im.convert("RGB")
75+
pixels = im.load()
76+
77+
# GENERATE IRIS ARRAY ------------------------------------------------------
78+
79+
counter = 0 # Reset outputHex() counters again for new table
80+
column = columns
81+
limit = im.size[0] * im.size[1]
82+
83+
print
84+
print "#define IRIS_MAP_WIDTH " + str(im.size[0])
85+
print "#define IRIS_MAP_HEIGHT " + str(im.size[1])
86+
print
87+
88+
sys.stdout.write("const uint16_t iris[IRIS_MAP_HEIGHT][IRIS_MAP_WIDTH] = {")
89+
90+
for y in range(im.size[1]):
91+
for x in range(im.size[0]):
92+
p = pixels[x, y] # Pixel data (tuple)
93+
outputHex(((p[0] & 0b11111000) << 8) | # Convert 24-bit RGB
94+
((p[1] & 0b11111100) << 3) | # to 16-bit value w/
95+
( p[2] >> 3), 4) # 5/6/5-bit packing
96+
97+
98+
# OPEN AND VALIDATE UPPER EYELID THRESHOLD MAP -----------------------------
99+
100+
try: filename = sys.argv[3]
101+
except: filename = "upper.png"
102+
im = Image.open(filename)
103+
if (im.size[0] != 128) or (im.size[1] != 128):
104+
sys.stderr.write("Image size must match screen size")
105+
exit(1)
106+
im = im.convert("L")
107+
pixels = im.load()
108+
109+
# GENERATE UPPER LID ARRAY -------------------------------------------------
110+
111+
counter = 0
112+
column = columns
113+
limit = im.size[0] * im.size[1]
114+
115+
print
116+
print "#define SCREEN_WIDTH " + str(im.size[0])
117+
print "#define SCREEN_HEIGHT " + str(im.size[1])
118+
print
119+
120+
sys.stdout.write("const uint8_t upper[SCREEN_HEIGHT][SCREEN_WIDTH] = {")
121+
122+
for y in range(im.size[1]):
123+
for x in range(im.size[0]):
124+
outputHex(pixels[x, y], 2) # 8-bit value per pixel
125+
126+
127+
# OPEN AND VALIDATE LOWER EYELID THRESHOLD MAP -----------------------------
128+
129+
try: filename = sys.argv[4]
130+
except: filename = "lower.png"
131+
im = Image.open(filename)
132+
if (im.size[0] != 128) or (im.size[1] != 128):
133+
sys.stderr.write("Image size must match screen size")
134+
exit(1)
135+
im = im.convert("L")
136+
pixels = im.load()
137+
138+
# GENERATE LOWER LID ARRAY -------------------------------------------------
139+
140+
counter = 0
141+
column = columns
142+
limit = im.size[0] * im.size[1]
143+
144+
print
145+
sys.stdout.write("const uint8_t lower[SCREEN_HEIGHT][SCREEN_WIDTH] = {")
146+
147+
for y in range(im.size[1]):
148+
for x in range(im.size[0]):
149+
outputHex(pixels[x, y], 2) # 8-bit value per pixel
150+
151+
152+
# GENERATE POLAR COORDINATE TABLE ------------------------------------------
153+
154+
try: irisSize = int(sys.argv[5])
155+
except: irisSize = 80
156+
slitPupil = False
157+
if irisSize % 2 != 0:
158+
sys.stderr.write("Iris diameter must be even value")
159+
exit(1)
160+
if irisSize < 0:
161+
irisSize = -irisSize
162+
slitPupil = True
163+
filename = "pupilMap.png" # HACKITY HACK, see notes later
164+
im = Image.open(filename) # OMG so wretched and hacky
165+
if (im.size[0] != irisSize) or (im.size[1] != irisSize):
166+
sys.stderr.write("Image size must match iris size")
167+
exit(1)
168+
im = im.convert("L")
169+
pixels = im.load()
170+
radius = irisSize / 2
171+
172+
print
173+
print "#define IRIS_WIDTH " + str(irisSize)
174+
print "#define IRIS_HEIGHT " + str(irisSize)
175+
176+
# One element per screen pixel, 16 bits per element -- high 9 bits are
177+
# angle relative to center point (fixed point, 0-511) low 7 bits are
178+
# distance from circle perimeter (fixed point, 0-127, pixels outsize circle
179+
# are set to 127).
180+
181+
counter = 0
182+
column = columns
183+
limit = irisSize * irisSize
184+
185+
sys.stdout.write("\nconst uint16_t polar[%s][%s] = {" % (irisSize, irisSize))
186+
187+
for y in range(irisSize):
188+
dy = y - radius + 0.5
189+
for x in range(irisSize):
190+
dx = x - radius + 0.5
191+
distance = math.sqrt(dx * dx + dy * dy)
192+
if(distance >= radius): # Outside circle
193+
outputHex(127, 4) # angle = 0, dist = 127
194+
else:
195+
if slitPupil:
196+
# TODO: add magic here
197+
# I totally cheated on the dragon eye
198+
# included with the demo code -- made a
199+
# canned distance bitmap using Illustrator +
200+
# Photoshop and use that...but it's rigged
201+
# to the bitmap size and isn't a generalized
202+
# solution, which is what's needed here.
203+
angle = math.atan2(dy, dx) # -pi to +pi
204+
angle += math.pi # 0.0 to 2pi
205+
angle /= (math.pi * 2.0) # 0.0 to <1.0
206+
distance = pixels[x, y] / 255.0
207+
else:
208+
angle = math.atan2(dy, dx) # -pi to +pi
209+
angle += math.pi # 0.0 to 2pi
210+
angle /= (math.pi * 2.0) # 0.0 to <1.0
211+
distance /= radius # 0.0 to <1.0
212+
distance *= 128.0 # 0.0 to <128.0
213+
a = int(angle * 512.0) # 0 to 511
214+
d = 127 - int(distance) # 127 to 0
215+
outputHex((a << 7) | d, 4)
216+

0 commit comments

Comments
 (0)