<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Insight VR &#187; pySight</title>
	<atom:link href="http://blog.insightvr.com/?feed=rss2&#038;cat=6" rel="self" type="application/rss+xml" />
	<link>http://blog.insightvr.com</link>
	<description>lasers, wiimote headtracking, games, visualizations</description>
	<lastBuildDate>Fri, 06 Aug 2010 21:34:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>PyCon Talk Up on Google Video</title>
		<link>http://blog.insightvr.com/?p=20</link>
		<comments>http://blog.insightvr.com/?p=20#comments</comments>
		<pubDate>Fri, 25 Apr 2008 00:43:54 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Head Tracking]]></category>
		<category><![CDATA[Lasers]]></category>
		<category><![CDATA[Marshie Attacks]]></category>
		<category><![CDATA[PyCon]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[pySight]]></category>
		<category><![CDATA[wiimote]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=20</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><embed id="VideoPlayback" style="width:400px;height:326px" flashvars="" src="http://video.google.com/googleplayer.swf?docid=-5373915899443275381&#038;hl=en" type="application/x-shockwave-flash"> </embed></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=20</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Laser Tracking with NumPy and PySight (and V4L too!)</title>
		<link>http://blog.insightvr.com/?p=17</link>
		<comments>http://blog.insightvr.com/?p=17#comments</comments>
		<pubDate>Sun, 06 Apr 2008 20:02:30 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Lasers]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[pySight]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=17</guid>
		<description><![CDATA[In my PyCon presentation (video should be up shortly video is up!) I mentioned the difficultly of processing the pixels fast enough. In a 640&#215;480 bitmap there are 307,200 pixels and the iSight is trying to pump them out at 30 frames per second. I did a few things to speed things up. For instance [...]]]></description>
			<content:encoded><![CDATA[<p>In my PyCon presentation (<span style="text-decoration: line-through;">video should be up shortly </span> <a href="http://blog.insightvr.com/?p=20">video is up!</a>) I mentioned the difficultly of processing the pixels fast enough.  In a 640&#215;480 bitmap there are 307,200 pixels and the iSight is trying to pump them out at 30 frames per second.  I did a few things to speed things up.  For instance I limited the area of the bitmap that I scanned based on calibration data, I only scanned every fourth pixel (every other pixel of every other row) and I only processed every fifth frame.  While this worked well enough, clearly it was not ideal.<br />
<span id="more-17"></span><br />
The day before my presentation I was speaking with Travis Vaught at the Enthought booth asking how they did their multi-touch stuff in Python.  Well it turns out that they don&#8217;t do all of it in Python, but Travis suggested that I try NumPy for the image processing.  I had some concept of what NumPy could could because of some brief use of it with work, but I hadn&#8217;t really delved into.</p>
<p>So during the lightning talks on Friday I was feverishly writing NumPy code with the hope of getting it running for my demo at 9am on Saturday.  At about 1 am Matt and I were finally convinced that it worked and went back to the hotel room, where I built another pair of IR glasses until 2 am.</p>
<p>This did not leave time for altering my presentation, so I left it out.  I did mention it briefly after demoing the 3D game, but I would guess that many listeners missed it.</p>
<p>In any case, I basically reimplemented the method I was using to filter for red pixels in NumPy, but now the system scans every pixel of every frame.  Also, rather than returning a single point where the laser is &#8220;seen&#8221; it returns a list of  points if there are multiple lasers.</p>
<p>The basic process is that I first look at just the R value of the RGB tuple.  You can filter out pixels that don&#8217;t have a high enough R value very quickly.</p>
<p>Once I have a list of candidate pixels I look at them in more detail, calculating their redness.</p>
<p>Then I define redness as:</p>
<p>redness = R*2 &#8211; G &#8211; B</p>
<p>Thus a white pixel would have a redness of zero.  A pure red pixel would have a redness of 510 (255*2-0-0).   Again, NumPy makes this process fast, but it isn&#8217;t nearly as fast as the first filter due to the fact that it includes a multiply and two adds.  In fact, I tried to run it without the first filter (which doesn&#8217;t affect results, only speed) and it slowed things down a lot.</p>
<p>Finally I sort the list of pixels by redness and then begin putting those pixels in a results list.  But if a pixel is within about 15 pixels of a pixel already in the results list it is assumed to be part of the same laser and excluded.  Currently I am also capping the return list to a length of 5, which also helps with performance in some instances.</p>
<p>Here&#8217;s the code as it currently stands, with what I hope are sufficiently copious comments.</p>
<pre>#! /usr/bin/env python -t
'''
isightlaser

scans for laser and manages list of laser hits
This is a poorly named class as it works with a vartiety
of webcam inputs, not just the iSight

'''

import numpy

# The cameras we've tested so far all have 640x480 resolution
CAMERA_MAX_X = 640
CAMERA_MAX_Y = 480
NUM_PIXELS = CAMERA_MAX_X * CAMERA_MAX_Y

# for RGBA data this is the matrix we multiply by to get redness
MUL_ARRAY = numpy.array([2,-1,-1,0])

# some libraries return bitmaps as BGRA ordered data, so
# this is the matrix we use to get redness
BGRA_MUL_ARRAY = numpy.array([-1,-1,2,0])

class IsightLaser(object):

def __init__(self, top=0, bottom=480, left=640, right=0, game_xy=(1024,768)):
self.queue = []
self.top = top
self.bottom = bottom
self.left = left
self.right = right
self.game_xy = game_xy
self.calibrate = True

# called when game surface is sized or resized
def set_game_xy(self, xy_pair):
self.game_xy= (xy_pair)

def pop(self):
if self.queue:
return self.queue.pop()
else:
return None

def has_elements(self):
return self.queue

def push(self, xy_pair, flip_y=False):
# any pixels seen during calibration are used to define
# the limits of what the camera can see
if self.calibrate:
print "calibrating"
x,y = xy_pair
if y &gt; self.top:
self.top = y
if y &lt; self.bottom:
self.bottom = y
if x &gt; self.right:
self.right = x
if x &lt; self.left:
self.left = x

else:
trans_pair = self.translate(xy_pair, flip_y)

self.queue.append(trans_pair)
print self.top, self.bottom, self.left, self.right, self.game_xy

def translate(self, xy_pair, flip_y=False):
# translate a point from camera coordinates to game world coordinates
x = self.game_xy[0] * (xy_pair[0] - self.left)/(self.right-self.left)

# some cameras have their origin in the upper left, others in the lower left
if flip_y:
y = self.game_xy[1] * (xy_pair[1] - self.top)/(self.bottom - self.top)
else:
y = self.game_xy[1]- self.game_xy[1] * (xy_pair[1] - self.top)/(self.bottom - self.top)
#print xy_pair , x,y
return (x,y)

def start_calibrate(self):
self.calibrate =True
self.top = 0
self.bottom = 480
self.left = 640
self.right = 0

def stop_calibrate(self):
print "STOP CAL"
self.calibrate = False

def process_buffer(self, image_buffer, rgba=4, flip_y=False, bgra=False):
global MUL_ARRAY
# convert from buffer type to numpy array
flat_array = numpy.frombuffer(image_buffer,numpy.uint8)

# convert from a (640*480*4) x 1 matrix to a (640*480) x 4 matrix
image_array =numpy.reshape(flat_array,(NUM_PIXELS,rgba))

# filter out one colum of the matrix in order to just get red values
if bgra:
reds = image_array[:,2]
else:
reds = image_array[:,0]
#print  "image arrary:", image_array
#print "reds", reds
#image_array =numpy.multiply(image_array,MUL_ARRAY)

# Filter out any red value that is less than 180 (should be adaptive later)
mask = numpy.greater(reds,180)
#print mask

# get indices of pixels with a red value over 180
original_indices = numpy.array(mask.nonzero())[0]
#print "original_indices", original_indices

# pixel_list is an n x 4 matrix of candidate pixels
pixel_list = numpy.array(image_array[original_indices])
#print "pixel list: ", pixel_list
if bgra:
MUL_ARRAY = BGRA_MUL_ARRAY

# next two lines multiply and then sum in order to get
# redness = 2*R - G - B + 0*A
pixel_list = numpy.multiply(pixel_list,MUL_ARRAY)
#print "after mul", pixel_list
pixel_list = pixel_list.sum(axis=1)
#print "after sum", pixel_list

# filter for redness over 300
pixel_indices = numpy.greater(pixel_list,300).nonzero()
#print "pixel ind", pixel_indices
red_pixels = numpy.array(pixel_list[pixel_indices])
#print "red pixels", red_pixels

# Work back to get the index of pixels that pass both
# filters
original_indices = original_indices[pixel_indices]
#print "original_indices", original_indices

# create an n x 2 matrix with redness values and indicies
combined_array = numpy.column_stack((red_pixels,original_indices))
#print "ca", combined_array

# sort by redness
combined_array = numpy.sort(combined_array,axis=0,kind='quicksort')
#print "sorted ca", combined_array
clean_list = []

# take reddest pixel first, put it in the list
# then take next reddest pixel and put it
# in the list if it isn't too close (sqrt(200) pixels)
# to a pixel already in the list
for pixel in combined_array[::-1]:  # this reverses the order from the sort
#print "pixel:", pixel
if clean_list.__len__() &gt; 5: #limits total number of dots tracked
break

x = pixel[1]%640
y = pixel[1]/640

add_elem = True
for clean_elem in clean_list:
if ((x-clean_elem[0])**2 + (y-clean_elem[1])**2) &lt; 200:
add_elem = False
break
if add_elem:
clean_list.append((x,y))

#print clean_list
for elem in clean_list:
self.push((elem[0],elem[1]), flip_y)

laser_singleton = IsightLaser()</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=17</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>WiiMote Head Tracking for Killing Marshie in 3D</title>
		<link>http://blog.insightvr.com/?p=13</link>
		<comments>http://blog.insightvr.com/?p=13#comments</comments>
		<pubDate>Tue, 25 Mar 2008 07:11:40 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Head Tracking]]></category>
		<category><![CDATA[Lasers]]></category>
		<category><![CDATA[Marshie Attacks]]></category>
		<category><![CDATA[PyCon]]></category>
		<category><![CDATA[pySight]]></category>
		<category><![CDATA[wiimote]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=13</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/d7BpSxxjAbY&#038;hl=en"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/d7BpSxxjAbY&#038;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=13</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Laser Missle Command Video Up</title>
		<link>http://blog.insightvr.com/?p=12</link>
		<comments>http://blog.insightvr.com/?p=12#comments</comments>
		<pubDate>Tue, 25 Mar 2008 03:34:33 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Lasers]]></category>
		<category><![CDATA[PyCon]]></category>
		<category><![CDATA[missile command]]></category>
		<category><![CDATA[pySight]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=12</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/VDHCkkN5jzo&#038;hl=en"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/VDHCkkN5jzo&#038;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=12</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Laser Missile Command Ported to Linux</title>
		<link>http://blog.insightvr.com/?p=11</link>
		<comments>http://blog.insightvr.com/?p=11#comments</comments>
		<pubDate>Mon, 24 Mar 2008 20:21:31 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Lasers]]></category>
		<category><![CDATA[missile command]]></category>
		<category><![CDATA[pySight]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=11</guid>
		<description><![CDATA[There is a new download up for Laser Missile Command.  This version now works with Linux as well as on the Mac.  My brother did the port so I don&#8217;t know all the details.  In fact, I don&#8217;t even remember exactly what webcam he has, but I know that it was purchased at SurplusComputers.com since [...]]]></description>
			<content:encoded><![CDATA[<p>There is a new download up for <a href="http://insightvr.com/download/LaserMissile0_02.zip">Laser Missile Command</a>.  This version now works with Linux as well as on the Mac.  My brother did the port so I don&#8217;t know all the details.  In fact, I don&#8217;t even remember exactly what webcam he has, but I know that it was purchased at <a href="http://www.surpluscomputers.com/store/main.aspx?p=SearchBody&amp;search=webcam">SurplusComputers.com</a> since we bought the laser pointers there at the same time.  I&#8217;ll have to have him post on the details.  If anybody out there is using Linux and wants to try this out I&#8217;d be interested in hearing how it works for you.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=11</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working Missile Command Posted!</title>
		<link>http://blog.insightvr.com/?p=6</link>
		<comments>http://blog.insightvr.com/?p=6#comments</comments>
		<pubDate>Mon, 17 Mar 2008 19:46:20 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Lasers]]></category>
		<category><![CDATA[PyCon]]></category>
		<category><![CDATA[missile command]]></category>
		<category><![CDATA[pySight]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=6</guid>
		<description><![CDATA[I spent the plane ride home ripping all traces of py2app out of my code. This has resulted in a version of the missile command game that can be installed with more ease on other computers. At least I think so. Please let me know what your experience is. The code is here and includes [...]]]></description>
			<content:encoded><![CDATA[<p>I spent the plane ride home ripping all traces of py2app out of my code.  This has resulted in a version of the missile command game that can be installed with more ease on other computers.  At least I think so.  Please let me know what your experience is.</p>
<p>The code is <a href="http://insightvr.com/download/LaserMissile0_01.zip">here</a> and includes a READ ME file, the text of which I&#8217;ve pasted below:</p>
<p><span id="more-6"></span> READ ME</p>
<p>IMPORTANT:<br />
Educate yourself about laser safety before using laser pointers with this game or for any project.</p>
<p>http://www.osha.gov/SLTC/laserhazards/</p>
<p>http://en.wikipedia.org/wiki/Laser_safety</p>
<p>More info and help available at:</p>
<p>http://insightvr.com</p>
<p>http://blog.insightvr.com</p>
<p>Laser Controlled Missile Command-like Game</p>
<p>This game demonstrates using PyGame and PySight to create a laser controlled video game.</p>
<p>The missileCommand.py file contains the bulk of the game and provides a cross-platform, mouse controlled PyGame implementation of something resembling Missile Command.  It requires that you have Python and PyGame installed.</p>
<p>Run it at the command line with:</p>
<p>python missileCommand.py</p>
<p>The laser control code is currently Mac OS X only.  It requires an iSight camera.  This can be a built-in iSight in a laptop or iMac.  It could also be an external iSight or any external fire-wire camera.  I have only tested with my built-in iSight and with a Sony DV camera.</p>
<p>I believe that running with laser control requires the following to be obtained and properly installed:</p>
<p>Red laser pointer(s)<br />
a projector or other external screen that is not connected to your iSight<br />
PySight from http://livingcode.blogspot.com/2005/10/pysight-preview.html<br />
CocoaSequenceGrabber from http://www.skyfell.org/cocoasequencegrabber.html<br />
NumPy<br />
PyObjC<br />
PyGame</p>
<p>Setup of the projector and camera isn&#8217;t too hard, but I&#8217;ll share some hints.  First, it needs to be dark.  The darker the better.  Second, the camera needs to have the entire screen in its field of view.  Note that it doesn&#8217;t need to fill its field of view.  You can check this quickly and easily by running PhotoBooth.  Finally you can do rear-projection or front projection, but I believe that the camera needs to be on the same side of the screen as the projector.  However the players do not.  Thus on Halloween I have my computer and projector safely in the garage, a sheet which serves as a screen in the door of the garage, and kids playing with lasers in the driveway.</p>
<p>Run the laser controlled version of the game with the following command line statement:</p>
<p>python main.py</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=6</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Got Pics?  Got Video?</title>
		<link>http://blog.insightvr.com/?p=5</link>
		<comments>http://blog.insightvr.com/?p=5#comments</comments>
		<pubDate>Sun, 16 Mar 2008 16:28:07 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Head Tracking]]></category>
		<category><![CDATA[Lasers]]></category>
		<category><![CDATA[Marshie Attacks]]></category>
		<category><![CDATA[PyCon]]></category>
		<category><![CDATA[missile command]]></category>
		<category><![CDATA[pySight]]></category>
		<category><![CDATA[wiimote]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=5</guid>
		<description><![CDATA[I completely failed to bring my camera to PyCon. If anyhow has pictures or video from either my presentation or the BOF session I&#8217;d love to hear from you and get copies. Thanks.]]></description>
			<content:encoded><![CDATA[<p>I completely failed to bring my camera to PyCon.  If anyhow has pictures or video from either my presentation or the BOF session I&#8217;d love to hear from you and get copies.  Thanks.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=5</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PyCon 2008 Presentation &#8211; Marshie Attacks</title>
		<link>http://blog.insightvr.com/?p=3</link>
		<comments>http://blog.insightvr.com/?p=3#comments</comments>
		<pubDate>Sat, 15 Mar 2008 21:03:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Head Tracking]]></category>
		<category><![CDATA[Lasers]]></category>
		<category><![CDATA[Marshie Attacks]]></category>
		<category><![CDATA[PyCon]]></category>
		<category><![CDATA[pySight]]></category>
		<category><![CDATA[wiimote]]></category>

		<guid isPermaLink="false">http://blog.insightvr.com/?p=3</guid>
		<description><![CDATA[I presented Marshie Attacks at PyCon 2008 today. This provided some motivation for getting the project posted online and whatnot. So I&#8217;ve put up this blog and also a very primitive project page at InsightVR.com to try to share this stuff. Feel free to post comments and ask questions and I&#8217;ll do my best to [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://insightvr.com/pics/MarshieDiagram640.jpg" alt="Marshie Concept" height="411" width="640" /></p>
<p>I presented Marshie Attacks at PyCon 2008 today.  This provided some motivation for getting the project posted online and whatnot.  So I&#8217;ve put up this blog and also a very primitive project page at <a href="http://insightvr.com" title="Insight VR" target="_blank">InsightVR.com</a> to try to share this stuff.</p>
<p><span id="more-3"></span></p>
<p>Feel free to post comments and ask questions and I&#8217;ll do my best to be responsive.  Hopefully I&#8217;ll be able to post more details, videos, and explanations as time goes on.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.insightvr.com/?feed=rss2&amp;p=3</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
