/****************************************************************************\
*
* (C) 2010 by Imagination Computer Services GesmbH. All rights reserved.
*
* Project: flare
*
* @author Stefan Hynst
*
\****************************************************************************/
package at.imagination.flare
{
import cmodule.libFlareNFT.CLibInit;
import flash.display.BitmapData;
import flash.display.Stage;
import flash.utils.ByteArray;
// ----------------------------------------------------------------------------
/**
* FlareNFT is a wrapper class providing convenient methods to use the
* functions provided by libFlareNFT.
For an example on how to use it see
* samples/TestNFT
.
*/
public class FlareNFT implements IFlareTracker
{
private var m_CLib:CLibInit;
private var m_logFunc:Function;
private var m_fileLoader:FilePreloader;
private var m_trackerLib:Object;
private var m_stage:Stage;
private var m_dataPath:String;
private var m_featureSetFile:String;
private var m_camFile:String;
private var m_camWidth:uint;
private var m_camHeight:uint;
private var m_camFPS:uint;
private var m_multiTargets:Boolean;
private var m_initDoneCB:Function;
private var m_alcMemory:ByteArray = null;
private var m_alcImagePointer:uint;
// ------------------------------------------------------------------------
public function FlareNFT()
{
m_logFunc = null;
m_CLib = new CLibInit();
m_trackerLib = m_CLib.init();
}
// ------------------------------------------------------------------------
/**
* Returns the version of flareNFT
*
* @return Version number as String formatted as major.minor.build
*/
public function getVersion():String
{
return (m_trackerLib.getVersion());
}
// ------------------------------------------------------------------------
/**
* Sets a logging function: Use this to display logging output from libFlareNFT.
*
* @param obj If the logging function is a method of an object, set this to
* the method's object. Otherwise pass null
*
* @param logger The logging function that will be called from libFlareNFT.
* The function must be of type function(int, String):void
*
* @param level Only produce logging output for log-levels <= level
*/
public function setLogger(obj:Object, logger:Function, level:uint):void
{
m_logFunc = logger;
m_trackerLib.setLogger(obj, logger, level);
}
// ------------------------------------------------------------------------
/**
* Initializes the tracker. This needs to be called before update()
*
* @param dataPath Path were all the datafiles (camera ini-file, feature-set file,
* database files and pgm-files) are located.
*
* @param stage The application's stage.
*
* @param camFile Name of the camera initalization file.
*
* @param camWidth Width of the camera input in pixels.
*
* @param camHeight Height of the camera input in pixels.
*
* @param camFPS Frames per second.
*
* @param featureSetFile Name of the feature set file.
*
* @param multiTargets Set this to true
if multiple targets should
* be tracked. This is only necessary, if we want to display more than one
* targets at the same time.
*
* @param initDoneCB Callback function to be invoked, when initialization has
* finished. This is necessary, because all input files will be loaded
* asynchronously before libFlareNFT can initialize the tracker.
* The function must be of type function():void
*/
public function init(stage:Stage,
dataPath:String, camFile:String, camWidth:uint, camHeight:uint, camFPS:uint,
featureSetFile:String, multiTargets:Boolean,
initDoneCB:Function):void
{
m_stage = stage;
m_dataPath = dataPath;
m_featureSetFile = featureSetFile;
m_camFile = camFile;
m_camWidth = camWidth;
m_camHeight = camHeight;
m_camFPS = camFPS;
m_multiTargets = multiTargets;
m_initDoneCB = initDoneCB;
if (m_stage != null)
{
// get absolute path and replace backslashes with slashes
var basePath:String = m_stage.loaderInfo.loaderURL.replace(/[\\]/g, "/");
// cut off query part
basePath = basePath.slice(0, basePath.indexOf("?"));
// cut off file name, keep last slash
basePath = basePath.slice(0, basePath.lastIndexOf("/") + 1);
// create preloader:
// all files needed by libFlareNFT have to be preloaded and passed
// to alchemy via m_Clib.supplyFile()
//
m_fileLoader = new FilePreloader(fileLoadedCB);
m_fileLoader.loadStart();
m_fileLoader.load("flareNFT.lic" , basePath);
m_fileLoader.load(m_camFile , m_dataPath);
m_fileLoader.load(m_featureSetFile, m_dataPath);
}
}
// ------------------------------------------------------------------------
/**
* Returns the projection matrix. Since the camera doesn't move during tracking,
* this needs to be called only once after init()
to obtain the
* projection matrix.
*
* @return The matrix is retured as a ByteArray
containing 4x4 Numbers.
*
* @example To set the projection matrix for a camera in
* papervison3D,
* you would do the following:
*
*
* var mat:ByteArray = flareTrackerNFT.getProjectionMatrix(); * var proj:Matrix3D = (_camera as Camera3D).projection; * * proj.n11 = mat.readFloat(); * proj.n21 = -mat.readFloat(); * proj.n31 = mat.readFloat(); * proj.n41 = mat.readFloat(); * * proj.n12 = mat.readFloat(); * proj.n22 = -mat.readFloat(); * proj.n32 = mat.readFloat(); * proj.n42 = mat.readFloat(); * * proj.n13 = mat.readFloat(); * proj.n23 = -mat.readFloat(); * proj.n33 = mat.readFloat(); * proj.n43 = mat.readFloat(); * * proj.n14 = mat.readFloat(); * proj.n24 = -mat.readFloat(); * proj.n34 = mat.readFloat(); * proj.n44 = mat.readFloat(); ** * Note that the 2nd row is inverted, because we need to convert from a * right-handed coordinate system (used by flare) to a left-handed * coordinate system (used by * papervison3D). */ public function getProjectionMatrix():ByteArray { if (! m_alcMemory) return null; m_alcMemory.position = m_trackerLib.getProjectionMatrixPtr(); return m_alcMemory; } // ------------------------------------------------------------------------ /** * This method needs to be called every frame to obtain the tracking results. * * @param image The bitmap grabbed from the camera. * * @return Number of targets found. */ public function update(image:BitmapData):uint { if (! m_alcMemory) return null; // write to "alchemy memory" m_alcMemory.position = m_alcImagePointer; m_alcMemory.writeBytes(image.getPixels(image.rect)); // returns number of targets found return (m_trackerLib.update()); } // ------------------------------------------------------------------------ /** * Returns the tracking results. Call this method after
update()
* found one or more targets.
*
* @return The tracking results are returned as a ByteArray
structure
* of the following form:
* * reserved:int; // reserved for later use * targetID:int; // unique identifier of the target * * poseMatrix_11:Number; // pose matrix: model view matrix of target in 3D space * poseMatrix_21:Number; * poseMatrix_31:Number; * poseMatrix_41:Number; * * poseMatrix_12:Number; * poseMatrix_22:Number; * poseMatrix_32:Number; * poseMatrix_42:Number; * * poseMatrix_13:Number; * poseMatrix_23:Number; * poseMatrix_33:Number; * poseMatrix_43:Number; * * poseMatrix_14:Number; * poseMatrix_24:Number; * poseMatrix_34:Number; * poseMatrix_44:Number; ** This structure is repeated in the
ByteArray
for every target found.
*
* @example This example shows how the tracker results can be parsed.
* * var targetID:int; * var mat:Matrix3D = new Matrix3D(); * var numTargets:uint = flareTrackerNFT.update(bitmap); * var targetData:ByteArray = flareTrackerNFT.getTrackerResults(); * * // iterate over all visible targets * for (var i:uint = 0; i < numTargets; i++) * { * targetData.readInt(); // unused * targetID = targetData.readInt(); * * // read pose matrix (= model view matrix) * mat.n11 = targetData.readFloat(); * mat.n21 = -targetData.readFloat(); * mat.n31 = targetData.readFloat(); * mat.n41 = targetData.readFloat(); * * mat.n12 = targetData.readFloat(); * mat.n22 = -targetData.readFloat(); * mat.n32 = targetData.readFloat(); * mat.n42 = targetData.readFloat(); * * mat.n13 = targetData.readFloat(); * mat.n23 = -targetData.readFloat(); * mat.n33 = targetData.readFloat(); * mat.n43 = targetData.readFloat(); * * mat.n14 = targetData.readFloat(); * mat.n24 = -targetData.readFloat(); * mat.n34 = targetData.readFloat(); * mat.n44 = targetData.readFloat(); * * // show target object and apply transformation * showObject(targetID, mat); * } ** * The 2nd row of the pose matrix is inverted to convert from a right-handed * coordinate system to a left-handed coordinate system. */ public function getTrackerResults():ByteArray { if (! m_alcMemory) return null; m_alcMemory.position = m_trackerLib.getTrackerResultPtr(); return m_alcMemory; } // ------------------------------------------------------------------------ /** * Returns the 2d-tracking results. Call this method after
update()
* found one or more targets.
*
* @return The 2d-tracking results are returned as a ByteArray
structure
* of the following form:
* * reserved:int; // reserved for later use * targetID:int; // unique identifier of the target * * // corner points of the target in image space * cornerUL_x:Number; // upper left corner point * cornerUL_y:Number; * * cornerUR_x:Number; // upper right corner point * cornerUR_y:Number; * * cornerLR_x:Number; // lower right corner point * cornerLR_y:Number; * * cornerLL_x:Number; // lower left corner point * cornerLL_y:Number; ** This structure is repeated in the
ByteArray
for every target found.
*
*/
public function getTrackerResults2D():ByteArray
{
if (! m_alcMemory) return null;
m_alcMemory.position = m_trackerLib.getTrackerResult2DPtr();
return m_alcMemory;
}
// ------------------------------------------------------------------------
/**
* Sets a button handler that will be invoked if a virtual button that was
* defined with the function addButton()
was pressed or released.
*
* @param obj If the button handler is a method of an object, set this to the
* method's object. Otherwise pass null
*
* @param handler The callback function that will be invoked whenever a virtual
* button was pressed or released. The function must be of type
* function(uint, uint, Boolean):void
.
*
* As first argument to the callback function the id of the button's target
* will be passed. The second argument is the button's id. The third argument
* is either true
(button was pressed) or
* false
(button was released).
*/
public function setButtonHandler(obj:Object, handler:Function):void
{
m_trackerLib.setButtonHandler(obj, handler);
}
// ------------------------------------------------------------------------
/**
* Adds a virtual button to a target. A virtual button is a rectangular area
* on the target that will be checked at runtime for occlusion.
*
* If this area is covered (e.g. by moving your finger over the button),
* a button press event is generated and the button handler function that
* was defined with setButtonHandler()
is called.
* A release event is triggered when the button is uncovered again.
*
* @param targetID The id of the target to add a button for. To find out the id
* of a target image, look at the assignments in the feature-set file.
*
* @param x0 The x-coordinate of the upper-left corner of the button
*
* @param y0 The y-coordinate of the upper-left corner of the button
*
* @param x1 The x-coordinate of the lower-right corner of the button
*
* @param y1 The y-coordinate of the lower-right corner of the button
*
* @param minCoverage The percentage of the area that needs to be covered
* to set the button's state to "blocked". This is a float value greater than
* 0 (0%) and smaller than 1 (100%).historyLength
frames the button has to be in blocked state
* in order to trigger a button press event.historyLength/frameRate
* seconds.