/**
   * Processes the next frame in the sequence.
   *
   * @param frame Next frame in the video sequence
   * @return If a fatal error occurred or not.
   */
  public boolean process(I frame) {
    // update the feature tracker
    tracker.process(frame);
    totalProcessed++;

    // set up data structures and spawn tracks
    if (totalProcessed == 1) {
      tracker.spawnTracks();
      tracker.setKeyFrame();

      worldToKey.set(worldToInit);
      worldToCurr.set(worldToInit);
      return true;
    }

    // fit the motion model to the feature tracks
    List<KeyFrameTrack> pairs = tracker.getPairs();
    if (!modelMatcher.process((List) pairs)) {
      return false;
    }

    // refine the motion estimate
    if (modelRefiner == null
        || !modelRefiner.fitModel(modelMatcher.getMatchSet(), modelMatcher.getModel(), keyToCurr)) {
      keyToCurr.set(modelMatcher.getModel());
    }

    // Update the motion
    worldToKey.concat(keyToCurr, worldToCurr);

    return true;
  }
  /**
   * Transforms the world frame into another coordinate system.
   *
   * @param oldWorldToNewWorld Transform from the old world frame to the new world frame
   */
  public void changeWorld(T oldWorldToNewWorld) {

    T worldToKey = (T) this.worldToKey.invert(null);
    worldToInit.concat(worldToKey, oldWorldToNewWorld);

    this.worldToKey.set(worldToInit);
    this.worldToKey.concat(keyToCurr, worldToCurr);
  }