The biggest trackball
The Big Red Ball has become the world’s largest trackball! This is another 1-day project by Eric Gradman of SyynLabs. I transformed a 3′ walking globe into a trackball. I mounted it on a wooden assembly featuring four ball-transfer casters from McMaster-Carr. I spring mounted a wireless Logitech mouse such that it maintains contact with the underside of the ball at all times. To spin the ball on the casters is to essentially “move the ground beneath the mouse.”
The Big Red Ball keeps winding up in some weird places…
Privacy is Dead – Lessons Learned from the Cloud Mirror
I just returned from two weeks at Sundance Film Festival 2010. I was invited to install my interactive art piece “The Cloud Mirror” in New Frontier on Main, the venue devoted to art and interactivity rather than film. The Cloud Mirror is a large portrait LCD TV which displays live video from a camera pointed at the viewer. Casual visitors see themselves live on-screen. Superimposed on the image is a “comic book thought bubble” containing a snarky message. This thought bubble follows the visitor’s face around the screen as they move.
For the adventurous, there is another option. A visitor can pick up a badge from a nearby kiosk. Each badge has printed on it a unique fiducial glyph and a unique numeric id. The visitor then registers at a computer kiosk. They enter the badge’s unique id and log in with Facebook Connect, authorizing my Cloud Mirror application to access their data. Alternately, they can fill out a form with their name, email address, and other questions. Facebook is just “easier.”
Returning to the Cloud Mirror itself, visitors see themselves reflected in the mirror; but instead of a generic message in their thought bubble, they instead see information culled directly from their Facebook profile! Their “favorites” (movies, music, activities) are there; their relationship status; their last status update. But the Cloud Mirror doesn’t stop with Facebook: the visitor’s birthday is used to fetch their horoscope. Their name is used to search IMDB for their movie credits (this is Sundance after all!) and the Internet Sex Offender Registry. All the information gathered in this way is packaged up into little messages that fit in a thought bubble (“I didn’t know my name matches 4 registered sex offenders!”)
But there’s another surprise waiting for those wearing bages: When seen in the Cloud Mirror, the fiducial glyph on the badge itself is replaced with a photograph. The visitor is confronted with a “virtual photo album” hanging around their neck, and in that photo album are photos downloaded from Facebook and Flickr photos, those embarassing photos which their Facebook friends tagged them in, and image searches on their name.
What About Privacy?
Do you feel uneasy about this? Are you filled with terror at the prospect of your ephemeral online identity rendered in full color on your face in public? I promise that feeling will pass. People grew comfortable with the Cloud Mirror in stages. The first stage is a casual encounter: walking briskly past the screen they catch a glimpse of their face, and pause to read what the Cloud Mirror has written in their thought bubble. Groups of people gather around: sometimes groups of friends, but often aggregations of random people brought together by the thrill of performing on camera for others. They see how many faces they can fit in the frame, take pictures of one another on camera phones, and laugh together.
And then, someone realizes that this is only part of the story. There’s a registration kiosk, and a pile of badges, and instructions that hint at what the Cloud Mirror *really* does. The ice already broken, the group lines up excitedly to log in to Facebook.
Sometimes, there’s a hold-out. Someone who clings a little more tightly than the others to their illusions of privacy. But peer pressure always wins out in the end. You’ve got a Facebook page… what could you possibly have to hide?
The last stage is when they return a day later. They bring their friends, their family, their spouse. People in their network whose lives they already know. They’re giving their friends the opportunity to share on the big screen. And who on Facebook doesn’t love that?
The Next Generation Cares Less Than You Do
It may seem obvious that a generation that’s had access to social networks since they learned to type would have notions of privacy different from your own. But there’s no clearer illustration of that than the Cloud Mirror. Over the course of the week, I saw groups of junior- and high-schoolers register with the Cloud Mirror without a moment’s hesitation. What happened next was even more fascinating. They would proceed to literally *shove* one another out from in front of the camera, hungry for a moment on stage presenting the social network they’d so carefully cultivated .
There wasn’t a hint of hesitation in their actions. To them, the Internet is for sharing.
If Asked For Your Password
The Internet is for sharing interests and relationships, answering quizzes, and telling the world what you had for breakfast. If there’s a text-input box on a web form labelled “Boxers or briefs,” you can bet that a significant fraction of visitors will cheerfully answer the question. This doesn’t trouble me… I’m guilty of over-sharing too.
What troubles me greatly however is one box in particular that people were willing to fill in: “PASSWORD:”
I used what’s called Facebook Connect to link the Cloud Mirror to people’s online profiles. Facebook Connect is a well-conceived solution to the age-old problem of maintaining separate usernames and password on each website. With Facebook Connect, a participating website can compel its visitors to login instead to Facebook. Facebook responds with the user’s credentials. As a side-effect, Facebook authorizes the website to access the user’s Facebook profile for the duration of the login session. Its growing in popularity, and for many the Connect login screen is a familiar sight.
But entering your username and password into a familiar login screen is simply not safe on any computer other than your own! To be sure, public computers have *never* been safe. What shocked me was the thoughtlessness with which people cheerfully entered a username and password… for the online account that secures a growing amount of their information throughout the Internet!
Implementing Facebook Connect on the Cloud Mirror was an afterthought. I assumed from the start that asking people to enter a username and password was simply too bold. It was by far the most popular way to register.
The lesson here is that if you give someone a shiny trinket, they’ll give you their password in return.
Conclusion
The Cloud Mirror was an oddity at Sundance Film Festival, but an oddity that attracted many thousands of people over the course of the festival, including Robert Redford himself.
For many it was a source of joy which they returned to over and over. For others, it was profoundly awkward. The girl who’s IMDB profile credited her with porn after porn. The woman whose thought bubble said “Facebook says I’m single!” Both she and the man she had just met froze like statues, unwilling to look at one another (too soon!) In my week at the Festival, I heard people discussing the Cloud Mirror over dinner, and showing one another the pictures they’d snapped.
The Cloud Mirror reveals our online identities, but it also reveals that we’re easily persuaded to exchange personal data for a shiny trinket or a quick laugh.
Read More...DMX Python module
I’ve released my Python module for communicating with DMX devices. Its been tested with the ENTTEC USB Pro module. You can find the module in the Cheese Shop.
Read More...Working OpenCV python bindings
I have long cursed the absence of working python bindings for OpenCV. However, with the recent release of OpenCV 2.0, there are new python bindings in the distribution that not only “just work,” but behave in an unexpected and wonderful way: OpenCV functions can manipulate numpy arrays in-place! It took an afternoon to get things properly compiled and seaworthy, but I can now use OpenCV’s Filter2D method to convolve a numpy array without any memory copies.
Compile OpenCV 2.0
- Download OpenCV from WillowGarage. Resist the temptation to use autotools. Use cmake instead. The INSTALL file has the details. Read the INSTALL file. Learn from my mistakes.
- Run make install. The python bindings will be installed… to the wrong place. If you’re using Ubuntu, you should move the installed module from /usr/local/python2.6/site-packages to /usr/local/python/dist-packages
- run ipython and import cv. If this works, you’re good to proceed. If if fails, you’ll be tempted to import opencv.cv. Resist. This is the old binding… this road ends in tears.
Some sample code
import cv
import numpy
a = numpy.arange(256).reshape((16,16)).astype('u1')
ipl = cv.CreateImageHeader(a.shape, cv.IPL_DEPTH_8U, 1)
cv.SetData(ipl, a, a.shape[1])
cv.Flip(ipl)
Observe the contents of the a array before and after the call to Flip. You’ll see that the OpenCV operation has operated on the underlying numpy data.
Now all I have to do is develop some simple SWIG bindings for PointGrey FlyCap SDK, and I can do much of my computer vision stuff in Python.
Update
Much to my surprise, HighGUI works in a python thread. The following code should be run in ipython. I can test out OpenCV operations on im and see the results live in the HighGUI window. Take that, C++
import cv
import threading
orig = cv.LoadImage("test.png")
im = cv.CloneImage(orig)
def waitkey():
cv.NamedWindow("debug")
while True:
cv.ShowImage("debug", im)
cv.WaitKey(45)
threading.Thread(target=waitkey).start()
Python code to decode SMS PDU
Internet, I was recently working on a project that required decoding incoming SMS messages from a T39 unlocked GSM phone over bluetooth. This was non-trivial. But for you, henceforth, it shall be trivial. For more information, see this place.
Copyright (c) 2009 Eric Gradman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
import serial
import time
from cStringIO import StringIO
from math import ceil
from binascii import unhexlify, hexlify
from itertools import *
class T39(object):
def __init__(self, file="/dev/tty.T39-SerialPort1-1"):
self.file = file
self.ser = serial.Serial(file, 115200)
self.pdu = PDU()
for s in ('ATZ', 'AT+CPMS="ME","ME","ME"', 'AT+CNMI=3,3,2,0,0'):
self.ser.write("%s\r" % s)
while True:
d=self.ser.readline()
print d
if d.startswith("OK"):
break
def fetch(self):
s = self.ser.readline()
return self.pdu.decode(s)
class PDU(object):
def decode(self, s):
s = unhexlify(s)
d = StringIO(s)
# parse SMSC information
p = {}
p['smsc_len'] = d.read(1)
p['type_of_address'] = d.read(1)
p['sc_num'] = self.unsemi(d.read(ord(p['smsc_len'])-1))
p['msg_type'] = d.read(1)
p['address_len'] = d.read(1)
p['type_of_address'] = d.read(1)
p['sender_num'] = self.unsemi(d.read(int(ceil(ord(p['address_len'])/2.0))))
p['pid'] = d.read(1)
p['dcs'] = d.read(1)
p['ts'] = d.read(7)
p['udl'] = d.read(1)
p['user_data'] = d.read(ord(p['udl']))
p['user_data'] = self.decode_user_data(p['user_data'])
return p
def decode_user_data(self, s):
"""PDU user data is stored in a strange 7-bit packed format"""
bytes = map(ord, s)
strips = cycle(range(1,9))
out = ""
c = 0 # carry
clen = 0 # carry length in bits
while len(bytes):
strip = strips.next()
if strip == 8:
byte = 0
ms = 0
ls = 0
else:
byte = bytes.pop(0)
# take strip bytes off the top
ms = byte >> (8-strip)
ls = byte & (0xff >> strip)
#print "%d byte %x ms %x ls %x" % (strip, byte, ms, ls)
# append the previous
byte = ((ls << clen) | c) & 0xff
out += chr(byte)
c = ms
clen = strip % 8
if strip == 7: out += chr(ls) # changed 6/11/09 to incorporate Carl's suggestion in comments
return out
def unsemi(self, s):
"""turn PDU semi-octets into a string"""
l = list(hexlify(s))
out = ""
while len(l):
out += l.pop(1)
out += l.pop(0)
return out
Read More... Code to scape CNN.com election results
My election party tomorrow will feature DMX controlled RGB LED lighting. The color of the house should reflect the electoral balance. The color will start purple, and drift toward either red or blue, depending on who’s winning.
We are hoping that as the night wears on, the room will turn more and more BLUE.
In order to do this, it was necessary to obtain live election results. Presented for your use is a simple python urllib2 scraper which will fetch live results from CNN.com.
Return value is ((dpopular, delectoral), (rpopular, relectoral)). Furthermore, when CNN calls the race, the get method throws an ElectionWon exception.
This code is in the public domain. The data, however, actually costs around $4000 if you buy it directly from exit-poll.net, the clearinghouse for aggregated exit poll data. Yikes!
UPDATED:
I’ve updated the code with a function that will normalize the results to -1 => democrat wins, 1 => republican wins. The function takes an interval argument which constrains the range over which the function is computed. That is to say, for interval == 0.25 this function returns -1.0 if Obama is winning by 25%.
I’m normalizing this from (republican_votes)/(democratic_votes+republican_votes). So it doesn’t matter what the format of that vote value is scaled to.
Read More...

