to prepare this movie you need the following you need open box sprites in channel 5 & 6 (targets for motion) you will need event id sprites (eg text) in channels 10,11,12 you will need sounds imported into cast with member's named to "event0","event1","event2" you will need digital movie imported into cast and placed in correct sprite you will need a following sprite (eg small ball) placed in channel 15 --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 on StartMovie global flag initvalues if flag = 1 then setupTTC startVideo 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 on initvalues global curevent, vidrect curevent = 0 vidrect = rect(0,0,320,240) 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 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 checkNew global TrackObj ,frect1, frect2, vidrect 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 masterVid 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 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 on masterVid global flag, frect1, frect2, tarrect1, tarrect2 global curevent, newevent tarrect1 = sprite(5).rect tarrect2 = sprite(6).rect newevent = 0 checkNew -- see if in place #1 -- go to appropriate frame if frect1 <> 0 then if intersect (frect1,tarrect1) <> rect(0,0,0,0) then newevent = 1 end if end if -- see if in place #2-- go to appropriate frame if frect2 <> 0 then if intersect (frect2,tarrect2) <> rect(0,0,0,0) then newevent = 2 end if end if -- 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 -- 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 ------------ frame scripts -- this script is put at beginning of event0 in frame script of frame 20 -- it assumes that sprite 10 has the appropriate image loaded for event0 -- it assumes that sprite 11 has event 1 image and sprite 12 have event 2 -- -- assumes that event0.wav is the appropriate sound for event 0 -- and that its link has been loaded into a cast member called sound0 -- it arbitraily plays it in sound channel 2 -- -- assumes that there is a link to a movie loaded into a cast member and t -- that movie is placed in sprite channel 13 -- place in script of frame 20 -- turn off other images (channels 21 and 22); turn on event 0 (channel 20) -- start playing sound0 -- jump to position 100 of the movie in sprite channel 13 on enterFrame sprite (11).visible = false sprite (12).visible = false sprite(10).visible = true sound(2).play(member("sound0")) sprite(13).movietime = 100 end -- place in frame 30 script to loop within sequence -- send it back to beginning +1 so don't restart sound/movie -- keep looping sound by checking if done (soundbusy(2) = false) and replay -- check if movie beyond the beginning of next segment, reset -- (if sprite(13).movietime> 400 ) on exitFrame if soundbusy(2) = false then sound(2).play(member("sound0")) end if if sprite(13).movietime> 400 then sprite(13).movietime = 100 sprite(13).movierate = 1 end if go frame marker("event0")+1 end exitFrame ----- -- place in script of frame 40 -- turn off other images (channels 20 and 22); turn on event 1 (channel 21) -- start playing sound1 -- jump to position 400 of the movie in sprite channel 13 on enterFrame sprite (10).visible = false sprite (12).visible = false sprite(11).visible = true sound(2).play(member("sound1")) sprite(13).movietime = 400 end -- place in frame 50 script to loop within sequence -- send it back to beginning +1 so don't restart sound/movie on exitFrame if soundbusy(2) = false then sound(2).play(member("sound1")) end if if sprite(13).movietime> 600 then sprite(13).movietime = 400 sprite(13).movierate = 1 end if go frame marker("event1")+1 end exitFrame -- place in script of frame 60 -- turn off other images (channels 20 and 21); turn on event 2 (channel 22) -- start playing sound2 -- jump to position 600 of the movie in sprite channel 13 on enterFrame sprite (10).visible = false sprite (11).visible = false sprite(12).visible = true sound(2).play(member("sound2")) sprite(13).movietime = 600 end -- place in frame 70 script to loop within sequence -- send it back to beginning +1 so don't restart sound/movie on exitFrame if soundbusy(2) = false then sound(2).play(member("sound2")) end if if sprite(13).movietime> 900 then sprite(13).movietime = 600 sprite(13).movierate = 1 end if go frame marker("event2")+1 end exitFrame