--NOTE - THIS IS IMPROVED VERSION DONE 1/5/03
-- ADDED FEATURES: tracks all rectangles/ can respond to more than
1
-- changes - checknew adds global found list that is sent
-- to new mastervidmultiple
-------------------
--The initialization routines are put in a startMovie handler
-- so they will be activated on startup
-- the initialization routine is put in subroutine called setupTTC
-- StartMovie
-- TrackObj is the variable that will contain the reference to the
xtra
-- All subsequent TrackThemColor functions will use it.
-- Flag = variable that indicates whether video tracking should be
active (= 1)
-- setupTTC = routine that will intialize the TTC xtra
-- startVideo = ttc routine that starts taking in video
-- takeRef = routine that takes snapshot of video to use (see section
III below)
-- initvalues = routine to set values for variables used later
-- the flag variable is explained down in section IV
-- it avoids calling the routines if ttc is not active
-- the starttimer routine puts a delay before calling take ref
-- to give time for startvideo to settle
on StartMovie
global flag
initvalues
if flag = 1 then
setupTTC
startVideo
starttimer
repeat while the timer < 200
end repeat
takeRef
end if
end startMovie
-- initvalues
-- Sets global variables curevent and vidrect
-- curevent is used later to tell where there is motion and what event
is active
-- vidrect is a rectangle telling how big the video image is
-- you might set other values here for your own movies
-- it is used in later routines
-- sprites 18,19,20 indicate events active
on initvalues
global curevent, vidrect
curevent = 0
vidrect = rect(0,0,320,240)
sprite(18).visible = false
sprite(19).visible = false
sprite(20).visible = false
end initvalues
-- setupTTC
-- The "if not TrackObj" checks whether you have already initialized
the xtra
-- The variable TrackObj will not have a value
-- the if statement will end up being false
-- and the inside of the if
-- statement then executes with the 'new' command
-- the reference to Xtra "TTCPro" must match the name of the
file
-- the variable TrackObjthen gets set to an address where the xtra
lives
-- that variable will be used in all the xtra routines
-- the name TrackObj is arbitrary - it can have any name
you want
-- as long as you are consistent in later references
on setupTTC
Global TrackObj
if not TrackObj then
set temp = Xtra "TTCPro"
set TrackObj = new(temp)
end if
end startTTC
-- startVideo
-- This next routine sets the xtra to start using the video signal
-- It is put in a subroutine called startVideo that is called
on startup
-- the xtra offers a command with parameters in the form
-- InitVideo(TrackObj, Source, SourceRect,VideoSource)
--
-- The TrackObj is the variable set above that references the xtra
--
-- Source indicates what kind of signal
-- 0 means track a quicktime or non live video;
-- 1 means usb or analog video
-- 2 means firewire or dv camera
--
-- SourceRect defines the resolution of the video signal by upper right
-- and lower left point coordinates
-- it should start with 0,0 for live video - eg (0,0,320,240)
-- To make it less confusing,
-- I generally make a variable to represent the video dimensions
-- using director's rect command (vidrect =rect(0,0,320,240)
-- the vidrect was set in the initialization routines
-- it must not be bigger than the video camera feed or it will get
garbage
-- NOTE - your vidrect may be bigger than this example eg (0,0,640,480)
--
-- VideoSource indicates which camera you are using
-- if you just have one camera it would be 1
-- if you had 2 cameras you could track both of them by using 1 and
2
-- in various different section. I suggest to start with just
one.
-- the example below shows the command in action
-- you would need to change the parameters as needed
on startVideo
--form for InitVideo(TrackObj, Source, SourceRect,VideoSource)
global trackObj, vidrect
--vidrect = rect(0,0,320,240)
InitVideo(TrackObj, 1, vidrect,1)
end startVideo
-- stopMovie
-- this routine closes the xtra by setting the global variable reference
= 0
-- it also stops the video tracking by calling the cleanup() function
-- the cleanup() function needs the variable trackObj reference so
it should
-- be called before the xtra is zeroed out
-- if you call the new again before cleaning up you can crash the xtra
or director
-- the cleanup is only called when flag = 1 -- meaning video tracking
has been inited
on StopMovie
global flag
if flag = 1 then
global TrackObj
CleanUp(TrackObj)
set TrackObj = 0
end if
end
-- takeRef
-- SET UP REFERENCE SNAPSHOT
-- this TakeRef routine sets up the reference frame
-- it sets up a search rectangle to define the active video area
-- it could be the whole rectangle of the video or some part
-- for example, if you knew all the important action was on the right
-- side of the screen, you would tell the xtra to ignore the left side
-- this makes it slightly faster and cuts out sources of possible noise
-- even if you do the whole frame, TTC documentation suggests
-- taking off 10 pixels around the edge because video often has noise
there
-- it uses the vidrect global variable set in initvalues routine at
start
--
-- the remember() function is provided by the xtra to create the ref
frame
-- it takes 2 parameters - TrackObj which is the varuabke with the
xtra
-- set up in the initialization routine and
-- a number that tells it where to get the video scence - 0 means live
feed
-- ohter numbers refer to cast members to use as refs
--
-- NOTE: depending on the nature of your installation, it might
be called
-- once or several times. If the reference frame never changes
(for example
-- a video of the installation with no one in it, then you would call
it once at
-- the beginning)
-- if there is something in the scene that is changing besides the
motion
-- of the people, then you would repeatedly call it to get a snapshot
-- to compare against - for example a moving object or projected video
or light change
on takeRef
global TrackObj,vidrect
videoWidth = vidrect[3]
videoHeight = vidrect[4]
set searchRect = rect(10,10,VideoWidth-10,VideoHeight-10)
grabOneframe(TrackObj)
Remember(TrackObj,0)
end
-- checkNew
-- ASK TTC IF THERE ARE ANY CHANGES
-- this checkNew routine sees if there has been change
-- and reports where the change is in the form of a list of rectangles
-- it cannot be called until a reference frame has been created (takeRef
see above)
-- typically you set your script so Director continually calls
-- the routine via an idle function (see IV below)
--
-- GrabOneFrame (TrackObj) is the function the xtra gives to get a
video
-- Another function GrabSomeFrames(TrackObj, Method, Frames)
-- grabs several frames and does some averaging. See docs for
more info
--
-- TrackColorBlobs(TrackObj, BlobList) is the function that
-- analyzes and identifies where the changes are
-- the parameter TrackObj is the xtra ref used in all functions
-- BlobList is a director list of areas to track and sensitiviies
-- in the example below just one area is tracked - the whole screen
-- thus the area to track is listed as the whole screen --
-- the variable searchRect just like what was used in GrabOneFrame()
-- you could list several different areas and similarity settings
-- for example, you might just be interested in left and right borders
-- see the docs for technical info
-- Similarity can be any number from 1 to 100; in the example
below =30
-- Higher numbers indicate higher threshold, less tolerance for difference
-- Notice that the parameters must be formatted in director's list
format
-- indicated with the enclosing square brackets [ ]
--
-- the xtra returns a list of rectangles where it found change
-- in a function called the result[1]
-- the routine below puts the result into a variable called foundList
-- the xtra will return a list of rectangles in all places it finds
change
-- some of them will be noise; you will have to sort that out
-- this improved routine returns a global variable called foundlist
-- it has all the rectangles of change that it found
on checkNew
global TrackObj ,frect1, frect2, vidrect,foundlist
videoWidth = getat(vidrect,3)
videoHeight = getat(vidrect,4)
set searchRect = rect(10,10,VideoWidth-10,VideoHeight-10)
GrabOneFrame(TrackObj)
BlobList = [40,searchRect]
trackchangeblobs(trackobj,[BlobList] )
-- get results
set foundList = the result[1]
end checkNew
--- this one grabs all the rectangles
-- and puts them in global variable called found list
-- mastervidmultiple uses that whole list
on checkNewmultiple
global TrackObj ,frect1, frect2, vidrect,foundlist
videoWidth = getat(vidrect,3)
videoHeight = getat(vidrect,4)
set searchRect = rect(10,10,VideoWidth-10,VideoHeight-10)
GrabOneFrame(TrackObj)
BlobList = [40,searchRect]
trackchangeblobs(trackobj,[BlobList] )
-- get results
-- frect1 = 0
-- frect2 = 0
-- set foundList = the result[1]
-- if foundList <> [] then -- is something there
-- frect1 = getat (foundList 1)
-- -- check more than one
-- if foundList.count > 1 then
-- frect2 = getat (foundList ,2)
-- end if
-- end if
end checkNew
-- idle
-- USE IDLE TO CHECKTRACKING IN USE AND RESPOND
-- Director constantly sends idle events
-- this routine checks what interface it should use
-- if flag = 1 then it goes to the video tracking using TTC
-- that subroutine is arbitraily called 'mastervid'
-- if flag = 2 then it goes to mouse based tracking
-- that subroutine is arbitraily called 'mastermouse'
-- if flag is any other value, then idle will do nothing
-- this choice allows you to turn off video tracking while you are
-- developing the program -- using the mouse to simulate movement
-- you will need to type in "flag = 1or2or0" before you start to
-- tell it what you want. Use the message box
-- the variable showflag controls whether the video feed will be displayed
-- if it is set to 1 it will call the showVid routine described below
on Idle
global flag,showflag
if flag = 1 then
masterVidmultiple -- note improved version
if showflag = 1 then
showVid
end if
end if
if flag = 2 then
masterMouse
end if
end idle
-- materVid
-- CHECK IF MOTION IN HOT SPOT AND RESPOND
-- This is the routine that sees if there is change within hot spots
-- you defined. It checks where the xtra is reporting motion.
-- It returns a rectangle pixel description. The routine above
-- called checkNew put all those rectangles in a list called foundlist
-- you need to set up hot spots. You can do this by turning on
the video
-- then drag open box sprites to surround the areas of interest
-- the rectangle of those sprites will then be the areas to watch for
motion
-- in the example below, the boxes have been put in sprite channel
5 & 6 & 7
-- if for some reason you didn't want actual sprites marking the areas,
-- you could use the boxes to get the coordinates and then create
-- artificial rectangle variables and get rid of the spritres
-- For example, you could substitute this line for "tarrect1 = sprite(5).rect"
-- tarrect1 = rect(10,30,100,120)
--
-- checkNew is the actual routine to call ttc to see if motion
-- the if routines below check to see if the xtra motion-detection
rectangle
-- intersects one of the hot spot rectangles
-- they use Director's intersect(rec1,rec2) function
-- this routine compares 2 rectangles and reports back rectangle coords
-- that enclose both rectangles. If they don't touch it gives
back
-- rect(0,0,0,0)
-- the routine below deducts that if the intersect is not equal to
(< >)
-- to the 0000 rect then there is an intersection and
-- motion has been detected near that area.
-- the routine sets up a repeat look that goes through the list of all
rectangles
-- found that was put in foundlist
-- it grabs each one with the getat(foundlist, n) function
-- it then checks whether each rectangle interects target areas indicated
-- by the tarrects (determined by location of sprites5,6,7)
-- if it finds an interesect it adds a 1,2,or 3 (indicating which event)
-- to the cumulative list variable called activelist
-- even if several rectangles intersect the targets it will add them
multiple times
-- thus activelist could look like this [1,2,2]
-- this ample would mean one rectctangle interesected target 1 and
two intersected target 2
-- in this example the next 3 if statements check to see
-- if activelist has any 1's, 2's or 3's indicating a motion
in target areas
-- it uses the getpos(list,n) function -- for example getpos(activelist,2)
-- this function will tell if there is a 2 in the list
-- getpos will tell where it is; it returns a 0 if it can't find any
-- thus meaning that there was not intersection in the 2 area
-- if there was an intersection, this sample turns on a sprite indicator
-- you could arrange for any kind of response you wanted
on masterVidmultiple
global flag, tarrect1, tarrect2,tarrect3, foundlist, activelist
--global frect1, frect2,
global curevent, newevent
tarrect1 = sprite(5).rect
tarrect2 = sprite(6).rect
tarrect3 = sprite(7).rect
newevent = 0
checkNew
--- go through all found rectangles
--- see if they interesect any target rectangles
-- add the number of target to activelist cummulative
list of all interesections
activelist = []
howmany = foundlist.count
repeat with z in foundlist
if intersect (z,tarrect1) <> rect(0,0,0,0) then
append activelist, 1
end if
if intersect (z,tarrect2) <> rect(0,0,0,0) then
append activelist, 2
end if
if intersect (z,tarrect3) <> rect(0,0,0,0) then
append activelist, 3
end if
--- could have checks with more targets here
end repeat
put "intersects detected- " & activelist into field
"allintersects"
-- check for 1,2.or 3 and respond
-- could do anything based on finding event
-- turn them on
if getpos(activelist,1) > 0 then -- event 1
--sprite(18).rect = sprite(5).rect
sprite(18).visible = 1
end if
if getpos(activelist,2) > 0 then -- event 2
--sprite(19).rect = sprite(6).rect
sprite(19).visible = 1
end if
if getpos(activelist,3)> 0 then -- event 3
-- sprite(20).rect = sprite(7).rect
sprite(20).visible = 1
end if
-- turn them off
if getone(activelist,1) = 0 then
sprite(18).visible = 0
end if
if getone(activelist,2) = 0 then
sprite(19).visible = 0
end if
if getone(activelist,3) = 0 then
sprite(20).visible = 0
end if
updatestage
end
-- masterMouse
--this routine reads mouse movement as though it was person movement
-- everything else in your movie will work the same if you set it up
right
-- the only thing different is the substitution for the intersect function
-- this routine checks if the mouseloc is inside the hot rectangles
-- Beware that the simulation is not perfect
-- for example, ttc makes more errors than the mouse movement detection
on masterMouse
global flag, tarrect1, tarrect2
global curevent, newevent
tarrect1 = sprite(5).rect
tarrect2 = sprite(6).rect
newevent = 0
-- see if in place #1 -- go to appropriate frame
if inside(the mouseloc,tarrect1) then
newevent = 1
end if
-- see if in place #2-- go to appropriate frame
if inside(the mouseloc,tarrect2) then
newevent = 2
end if
if curevent <> newevent then
if newevent = 1 then
go frame "event1"
set curevent = 1
end if
if newevent = 2 then
go frame "event2"
set curevent = 2
end if
if newevent = 0 then
go frame "event0"
set curevent = 0
end if
end if
end masterMouse
-- masterVidalt
-- tracks the motion and places sprite 15 at the location on screen
-- it uses the top right corner of the found rectangle as the place
to put the sprite
-- frect[1] gets x coordinate and frect[2] gets y coordinate
-- it then makes a point out of the two coordinates and sets the location
of sprite
-- to that location
-- the routine can be used to develop the movie without ttc and videotracking
active
-- for example, you could develop what media events happen
on masterVidalt
global flag, frect1
checkNew
if frect1 <> 0 then
x1 = frect1[1]
y2 = frect1[2]
z = point(x1,y2)
sprite(15).loc = z
end if
end masterVidalt
-- showVid
-- this routine will show the video feed from the source rect of the
video
-- in the targetrect of the stage (in this example the same as sourceRect)
-- it is useful for checking if video is live and where things are
-- it may not be useful in the actual event so it should
-- be set off and on with a flag (showflag in this example)
on showVid
global TrackObj
sourceRect = rect(0,0,320,240)
targetRect = sourcerect
GrabOneFrame(TrackObj)
ShowVideo(TrackObj,[sourceRect,targetRect])
end showVid
----------routines from the original
-- used 2 rectangles
-- this sample routine shows how to take the first 2 rectangles returned
-- you might want to adjust for more although often 2 is enough
-- this routine first checks if the foundlist has anything in it
-- the xtra will return empty list [ ] if there is nothing
-- the variables to store the rects (frect1 and frect2) are reset to
0
-- note that they are set as global variables so other routines can
use them
-- if foundlist is not empty, it uses director function
getat(list,1) to get the
-- first rectangle and puts it in frect1
-- if then checks if the count of lists in foundlist is greater
than 1
-- if it is, it gets the next one using getat (foundList ,2)
-- and puts it into frect2
-- these are the variables your other routines will use to run the
event
--on checkNeworig
-- global TrackObj ,frect1, frect2, vidrect,foundlist
-- videoWidth = getat(vidrect,3)
-- videoHeight = getat(vidrect,4)
-- set searchRect = rect(10,10,VideoWidth-10,VideoHeight-10)
--
-- GrabOneFrame(TrackObj)
-- BlobList = [40,searchRect]
-- trackchangeblobs(trackobj,[BlobList] )
--
-- -- get results
-- frect1 = 0
-- frect2 = 0
-- set foundList = the result[1]
-- if foundList <> [] then -- is something there
-- frect1 = getat (foundList 1)
-- -- check more than one
-- if foundList.count > 1 then
-- frect2 = getat (foundList ,2)
-- end if
-- end if
--
--end
----------------++++++++++++
-- part of original mastervid
-- materVid
-- CHECK IF MOTION IN HOT SPOT AND RESPOND
-- This is the routine that sees if there is change within hot spot
-- you defined. It checks where the xtra is reporting motion.
-- It returns a rectangle pixel description. The routine above
-- called checkNew put those rectangles in variables frect1 and frect2
-- you need to set up hot spots. You can do this by turning on
the video
-- then drag open box sprites to surround the areas of interest
-- the rectangle of those sprites will then be the areas to watch for
motion
-- in the example below, the boxes have been put in sprite channel
5 & 6
-- if for some reason you didn't want actual sprites marking the areas,
-- you could use the boxes to get the coordinates and then create
-- artificial rectangle variables and get rid of the spritres
-- For example, you could substitute this line for "tarrect1 = sprite(5).rect"
-- tarrect1 = rect(10,30,100,120)
--
-- newevent is a variable to check where motion is
-- it is initialized to a value of 0 to indicate no motion in hot area
-- checkNew is the actual routine to call ttc to see if motion
-- the if routines below check to see if the xtra motion-detection
rectangle
-- intersects one of the hot spot rectangles
-- they use Director's intersect(rec1,rec2) function
-- this routine compares 2 rectangles and reports back rectangle coords
-- that enclose both rectangles. If they don't touch it gives
back
-- rect(0,0,0,0)
-- the routine below deducts that if the intersect is not equal to
(< >)
-- to the 0000 rect then there is an intersection and
-- motion has been detected near that area. Newevent is set equal
to 1 or 2
-- if there have been no intersections then newevent is still 0
-- Note this design would need to be changed if you were trying to
detect
-- several motions in different hotspots at the same time
-- or just trying to track motion whereever it goes (see vidMasteralt
below)
--
-- the series of 3 if statements branch Director to different places
-- based on what ttc has detected
-- if there is motion near hotspot 1 it goes to a series of frames
-- that we arbitrailly named "event1", "event2", or "event0"
-- this is where the action happens - see section VI below
-- before testing for the intersection the routines make sure
-- that frect1 and frect2 are not equal (< >) 0
-- if they are equal to 0 director would give error because they were
-- not the rectangles that the intersect function needs.
--
-- Notice the check to see if newevent <> curevent
-- curevent is a variable that tells what is the current active event
-- if people were near hot spot 1 before and the xtra picks up new
-- motion there, we don't want to start event 1 over again
-- thus we use the comparison of the newevent and the current event
-- if they are the same we don't have to go anywhere because
-- we are already in the midst of that event
-- if they are not the same (< >) then we branch to the new place
-- and set the variable curevent to the new value
--
--
-- -- branch to right section of movie
-- if curevent <> newevent then
-- if newevent = 1 then
-- go frame "event1"
-- set curevent = 1
-- end if
--
-- if newevent = 2 then
-- go frame "event2"
-- set curevent = 2
-- end if
--
-- if newevent = 0 then
-- go frame "event0"
-- set curevent = 0
-- end if
--
-- --put frect1&&frect2 --&& if you
wanted to see what motion was detected
-- -- you would take out the comments and it would
print rectangles ttc found
-- -- in the message box
--
-- end if
--
--end