Published

Go There

Urban 5x5x5x5x15 Project Site selection for Provocation 3: International House corner

Full instructions provided682

Code

tracker.py

Python
tracker.py
```#!/usr/bin/env python

import os
import cv
import time
import sys
import math
import re
import serial
import pygame
import time
import numpy
from datetime import datetime, timedelta
from ConfigParser import *

CAMERA = 1

class Source:
def __init__(self, id, flip=True):
self.capture = cv.CaptureFromCAM(CAMERA)

def grab_frame(self):
self.frame = cv.QueryFrame(self.capture)
if not self.frame:
print "can't grab frame"
sys.exit(2)
cv.Flip(self.frame, None, 1)
return self.frame

class Music:
def __init__(self):
self.songs = []
self.staticWidth = .2
self.staticRange = self.staticWidth * 2;

pygame.init()
pygame.mixer.init()

self.staticSoundFile = pygame.mixer.Sound("static.wav")
self.staticSoundFile.set_volume(0)
self.staticSoundFile.play(loops=-1)

for singleSong in self.songs:
singleSong.play(loops=-1)

self.muteAll()

def setVolumesForPosition(self, position):
div = 1.0 / (2*len(self.songs))
#set song volume
for x in numpy.arange(div, 1, 2*div):
diff = abs(x - position)
song = int(x * len(self.songs))

if diff <= div:
audioLevel = 1 - diff / div
self.songs[song].set_volume(audioLevel)
else:
#audioLevel = 0.5 * self.songs[i].get_volume()
self.songs[song].set_volume(0)

#set static volume
for x in numpy.arange(2*div, 1 - div, 2*div):
diff = abs(x - position)
if (diff <= div/2):
audioLevel = 1 - diff/div
self.staticSoundFile.set_volume(audioLevel)
break
else:
self.staticSoundFile.set_volume(0)

# mappedPosition = position * (len(self.songs) - 1)
# for i in range(len(self.songs)):
#     difference = abs(i - mappedPosition)
#     if difference < .5:
#         audioLevel = 1 - (2 * difference)
#         self.songs[i].set_volume(audioLevel)
#     else:
#         self.songs[i].set_volume(0)
# # Static controled by global var static width
# justDecimal = mappedPosition - int(mappedPosition)
# if justDecimal > (.5 - self.staticWidth) and (justDecimal < .5 +  self.staticWidth):
#     shiftedDown = justDecimal - ((.5 - self.staticWidth))
#     staticLevel = 0
#     if shiftedDown < self.staticWidth: ##going up
#         staticLevel = shiftedDown/ self.staticWidth
#     else: #going down
#         staticLevel = self.staticRange - shiftedDown
#         staticLevel = staticLevel/ self.staticWidth
#         self.staticSoundFile.set_volume(staticLevel)
# else:
#     self.staticSoundFile.set_volume(0)

soundFile = pygame.mixer.Sound(myString)
soundFile.set_volume(0)
self.songs.append(soundFile)

def muteAll(self):
for singleSong in self.songs:
singleSong.set_volume(0)

class Setup:
def __init__(self):
self.mixer = None
self.source = Source(self.cameraid)
self.storage = cv.CreateMemStorage(0)
self.orig = self.source.grab_frame()

self.lastDetected = datetime.now()
self.last = 0
self.old_center = (0,0)
self.width = self.orig.width
self.height = self.orig.height
self.size = (self.width, self.height)
self.smallheight = self.working_height
self.smallwidth = int(self.width * self.smallheight/self.height * 1.0)
self.smallsize = (self.smallwidth, self.smallheight)

# alloc mem for images used at various stages
self.small = cv.CreateImage(self.smallsize, cv.IPL_DEPTH_8U, 3)
self.motion = cv.CreateImage(self.smallsize, cv.IPL_DEPTH_8U, 3)
self.eye = cv.CreateImage(self.smallsize, cv.IPL_DEPTH_8U, 3)
self.mhi = cv.CreateImage(self.smallsize, cv.IPL_DEPTH_32F, 1)
self.orient = cv.CreateImage(self.smallsize,cv.IPL_DEPTH_32F, 1)
self.temp = cv.CreateImage(self.smallsize, cv.IPL_DEPTH_8U, 3)
self.buf = range(10)
for i in range(self.n_frames):
self.buf[i] = cv.CreateImage(self.smallsize, cv.IPL_DEPTH_8U, 1)
cv.SetZero(self.buf[i])

self.combined = cv.CreateImage((self.smallwidth * self.xwindows, self.smallheight), cv.IPL_DEPTH_8U, 3)

if self.store:
self.writer = cv.CreateVideoWriter(self.output, 0, 15, cv.GetSize(self.combined), 1)

# make window
#cv.NamedWindow("Motion Detection")

#cv.CreateTrackbar('Height', 'Motion Detection', self.height_value, 100, self.change_height)

#cv.CreateTrackbar('Jitter', 'Motion Detection', self.jitter_value, 100, self.change_jitter)

def setMixer(self, mixer):
self.mixer = mixer

FileName = re.sub(r'\.py\$', "", os.path.abspath( __file__ )) + '.ini'
self.cp=ConfigParser()
try:
# f.close()
except IOError:
raise Exception,'NoFileError'

self.store = self.cp.getboolean('Variables', 'store')
self.cameraid = self.cp.getint('Variables', 'cameraid')
self.output = self.cp.get('Variables', 'output')
self.FPS = self.cp.getint('Variables', 'fps')
self.xwindows = self.cp.getint('Variables', 'xwindows')
self.working_height = self.cp.getint('Variables', 'working_height')
self.clocks_per_sec = self.cp.getfloat('Variables', 'clocks_per_sec')
self.mhi_duration = self.cp.getfloat('Variables', 'mhi_duration')
self.max_time_delta = self.cp.getfloat('Variables', 'max_time_delta')
self.min_time_delta = self.cp.getfloat('Variables', 'min_time_delta')
self.n_frames = self.cp.getint('Variables', 'n_frames')
self.height_value = self.cp.getint('Variables', 'height_value')
self.jitter_value = self.cp.getint('Variables', 'jitter_value')

return

def process_motion(self,img):
center = (-1, -1)
# a lot of stuff from this section was taken from the code motempl.py,
#  openCV's python sample code
timestamp = time.clock() / self.clocks_per_sec # get current time in seconds
idx1 = self.last
cv.CvtColor(img, self.buf[self.last], cv.CV_BGR2GRAY) # convert frame to grayscale
idx2 = (self.last + 1) % self.n_frames
self.last = idx2
silh = self.buf[idx2]
cv.AbsDiff(self.buf[idx1], self.buf[idx2], silh) # get difference between frames
cv.Threshold(silh, silh, 30, 1, cv.CV_THRESH_BINARY) # and threshold it
cv.UpdateMotionHistory(silh, self.mhi, timestamp, self.mhi_duration) # update MHI
(self.mhi_duration - timestamp)*255./self.mhi_duration)
cv.SetZero(img)
seq = cv.SegmentMotion(self.mhi, self.segmask, self.storage, timestamp, self.max_time_delta)
inc = 0
a_max = 1000
max_rect = -1

# there are lots of things moving around
#  in this case just find find the biggest change on the image
for (area, value, comp_rect) in seq:
if comp_rect[2] + comp_rect[3] > 10: # reject small changes
if area > a_max:
a_max = area
max_rect = inc
inc += 1

# found it, now just do some processing on the area.
if max_rect != -1:
(area, value, comp_rect) = seq[max_rect]
color = cv.CV_RGB(255, 0,0)
silh_roi = cv.GetSubRect(silh, comp_rect)
# calculate number of points within silhouette ROI
count = cv.Norm(silh_roi, None, cv.CV_L1, None)

# this rectangle contains the overall motion ROI
cv.Rectangle(self.motion, (comp_rect[0], comp_rect[1]),
(comp_rect[0] + comp_rect[2],
comp_rect[1] + comp_rect[3]), (0,0,255), 1)

# the goal is to report back a center of movement contained in a rectangle
# adjust the height based on the number generated by the slider bar
h = int(comp_rect[1] + (comp_rect[3] * (float(self.height_value) / 100)))
# then calculate the center
center = ((comp_rect[0] + comp_rect[2] / 2), h)

return center

def dejitter(self, center):
# if the center was not found, just draw the center on the old location.
if center == (-1,-1):
color  = cv.CV_RGB(0,225,0)
r = 15 * .7
self.old_center = self.old_center
else:
# anti-jittering section
x1 = self.old_center[0]
y1 = self.old_center[1]
x2 = center[0]
y2 = center[1]
dx = x2 - x1
dy = y2 - y1
d = math.sqrt( (dx)**2 + (dy)**2 ) # calculate a distance from old location to new.
angle = math.atan2(dy, dx)  # get an angle while we're doing the math

if d > self.jitter_value: # if the distance is really far....
self.old_center = (x2, y2)
# calculate a near point that exists on the line between the old and new point
self.old_center = (cv.Round(x1 + self.jitter_value * math.cos(angle)),
cv.Round(y1 + self.jitter_value * math.sin(angle)))
# and draw it
r = 15
color  = cv.CV_RGB(225,0,0)
else: # the distance is not far so just draw it
self.old_center = (x2, y2)
r = 15
color  = cv.CV_RGB(0,225,0)

return(r, color)

def pipeline(self):
presentation = []
self.orig = self.source.grab_frame()
cv.Resize(self.orig, self.small)

size = self.smallsize

# store the raw image
presentation.append((self.small, 'raw'))

self.motion = cv.CloneImage(self.small)

# location of the thingy moving on the screen is defined by center
center = self.process_motion(self.motion)

# if an object is found draw the circle on the same location.
if center != (-1,-1):
cv.Circle(self.motion, center, cv.Round(15), cv.CV_RGB(0,225,0), 3, cv.CV_AA, 0)
self.mixer.setVolumesForPosition(center[0] / float(self.smallwidth))
self.lastDetected = datetime.now()
else:

if datetime.now() - self.lastDetected > timedelta(seconds=7) and (abs(self.old_center[0] - self.smallwidth/2) > self.smallwidth/4):
self.mixer.muteAll()
elif datetime.now() - self.lastDetected > timedelta(minutes=15):
self.mixer.muteAll()
else:
self.mixer.setVolumesForPosition(self.old_center[0] / float(self.smallwidth))

# store the picture
presentation.append((self.motion, 'motion'))

####
# processing of final image
self.eye = cv.CloneImage(self.small) # get a copy

(r, color) = self.dejitter(center)
cv.Circle(self.eye, self.old_center, cv.Round(r), color, 3, cv.CV_AA, 0)

presentation.append((self.eye, 'final'))

# combine and show the results
combined = self.combine_images(presentation)
cv.ShowImage('Motion detection', combined )

if self.store:
cv.WriteFrame(self.writer, self.combined)

def change_jitter(self, position):
self.jitter_value = position

def change_height(self, position):
self.height_value = position

def combine_images(self, images):

font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 1.4, 1.4, 0, 2, 8)

for i,(image, name) in enumerate(images):
if image.nChannels == 1:
cv.Merge(image, image, image, None, self.temp)
else:
cv.Copy(image, self.temp)
xoffset = (i % self.xwindows) * self.smallsize[0]
yoffset = (i / self.xwindows) * self.smallsize[1]
cv.SetImageROI(self.combined, (xoffset, yoffset, self.smallsize[0],
self.smallsize[1]))
cv.Copy(self.temp, self.combined)
cv.PutText(self.combined, name, (5, 40), font, (30, 200, 200))
cv.ResetImageROI(self.combined)
return self.combined

def run(self):
while True:
t = time.time()
self.pipeline()
wait = max(2, (1000/self.FPS)-int((time.time()-t)*1000))
c = cv.WaitKey(wait) % 0x100
if c == 27 or c == 10:
break

if __name__ == '__main__':
s = Setup()
mixer = Music()
s.setMixer(mixer)
s.run()
```

Credits

Sahana Rajasekar

5 projects • 5 followers

Kevin Simons

3 projects • 0 followers
Senior studying Electrical Engineering and Computer Science at UC: Berkeley

Clare Lin

5 projects • 1 follower
I enjoy reading fiction, playing music and games, and consuming dark chocolate and jasmine green milk tea, though generally not all at the same time.

Amir Mohtashami

4 projects • 4 followers