Annotated script from improved version of ttc demo by Steve Wilson

 

 

--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