Documentation

Object Tracking

Introduction to Object Tracking

Object Recognition and Tracking extends the capabilities of the Wikitude SDK to recognize and track arbitrary objects for augmented reality experiences. The feature is based on Wikitude's SLAM engine that is also used for Instant Tracking. Object Tracking let you detect objects, that were pre-defined by you. Suitable objects include

  • Toys
  • Monuments and statues
  • Industrial objects
  • Tools
  • Household supplies

Simple Object Tracking

The Simple Object Tracking sample should just give you a rough idea of how object tracking works with the Wikitude Native SDK. We will track a toy fire truck and add a stroked cube as well as an occluder cube to demonstrate its use.

Object Tracking means that instead of tracking an image we track 3-dimensional objects, using information that has been extracted from a video of that object. This is why instead of a Wikitude Target Collection (.wtc) we use a .wto-file (Wikitude Object Target Collection) in this sample.

To use object tracking with the Wikitude Native SDK we have to make our Activity implement the ObjectTrackerListener interface and we will need to create an ObjectTracker as well as a StrokedCube and an OccluderCube using the GLRenderer class.

public class ObjectTrackingActivity extends Activity implements ObjectTrackerListener, ExternalRendering

After creating and initializing the Wikitude Native SDK object we create a TargetCollectionResource that points to the firetruck_map.wto (Wikitude Object Target Collection) file and hand it over to the TrackerManager's createObjectTracker method to create the object tracker, passing the Activity as the listener.

mTargetCollectionResource = mWikitudeSDK.getTrackerManager().createTargetCollectionResource("file:///android_asset/firetruck_map.wto", new TargetCollectionResourceLoadingCallback() {
    @Override
    public void onError(int errorCode, String errorMessage) {
        Log.v(TAG, "Failed to load target collection resource. Reason: " + errorMessage);
    }

    @Override
    public void onFinish() {
        mWikitudeSDK.getTrackerManager().createObjectTracker(mTargetCollectionResource, ObjectTrackingActivity.this, null);
    }
});

In the onObjectRecognized method we allocate a SrokedCube instance and an OccluderCube instance and register it with the renderer under the name of the recognized target.

@Override
public void onObjectRecognized(ObjectTracker tracker, final ObjectTarget target) {
    [...]

    StrokedCube strokedCube = new StrokedCube();
    OccluderCube occluderCube = new OccluderCube();

    mGLRenderer.setRenderablesForKey(target.getName(), strokedCube, occluderCube);
}

Correspondingly, the cube instances are unregistered again when the target is lost.

@Override
public void onObjectLost(ObjectTracker tracker, final ObjectTarget target) {
    [...]

    mGLRenderer.removeRenderablesForKey(target.getName());
}

The cubes are updated within the onObjectTracked method. The instances are retrieved from the renderer using the supplied target name and are subsequently updated using the information stored in the ObjectTarget parameter. The 0.5 offset on the Y-axis accounts for the origin being on the bottom of the object rather than the center in this particular map.

@Override
public void onObjectTracked(ObjectTracker tracker, final ObjectTarget target) {
    StrokedCube strokedCube = (StrokedCube)mGLRenderer.getRenderableForKey(target.getName());
    if (strokedCube != null) {
        strokedCube.projectionMatrix = target.getProjectionMatrix();
        strokedCube.viewMatrix = target.getViewMatrix();

        strokedCube.setYTranslate(0.5f);

        strokedCube.setXScale(target.getTargetScale().getX());
        strokedCube.setYScale(target.getTargetScale().getY());
        strokedCube.setZScale(target.getTargetScale().getZ());
    }

    OccluderCube occluderCube = (OccluderCube)mGLRenderer.getOccluderForKey(target.getName());
    if (occluderCube != null) {
        occluderCube.projectionMatrix = target.getProjectionMatrix();
        occluderCube.viewMatrix = target.getViewMatrix();

        occluderCube.setYTranslate(0.5f);

        occluderCube.setXScale(target.getTargetScale().getX());
        occluderCube.setYScale(target.getTargetScale().getY());
        occluderCube.setZScale(target.getTargetScale().getZ());
    }
}

Finally, similar to the other samples we implement onTargetsLoaded and onErrorLoadingTargets to simply log to the console to provide information about the loading process.

@Override
public void onTargetsLoaded(ObjectTracker tracker) {
    Log.v(TAG, "Object tracker loaded");
}

@Override
public void onErrorLoadingTargets(ObjectTracker tracker, int errorCode, final String errorMessage) {
    Log.v(TAG, "Unable to load image tracker. Reason: " + errorMessage);
}

If you add all this to your code, an orange cube will be displayed around the fire truck if you look at it. Since the occluder cube is always at the same posititon as the cube, you can't see the cubes sides that are farther away from the camera since the occluder blocks the view.

Simple Object Tracking