docs: protected boolean trackFeature() {
  
  		pairs.reset();
  		// total number of tracks which contribute to FB error
  		int numTracksFB = 0;
  		// tracks which are not dropped
  		int numTracksRemaining = 0;
  
  		for( int i = 0; i < tracks.length; i++ ) {
  			Track t = tracks[i];
  			if( !t.active )
  				continue;
  
  			float prevX = t.klt.x;
  			float prevY = t.klt.y;
  
  			// track in forwards direction
  			tracker.setImage(currentImage,currentDerivX,currentDerivY);
  			KltTrackFault result = tracker.track(t.klt);
  			if( result != KltTrackFault.SUCCESS ) {
  				t.active = false;
  				continue;
  			}
  
  			float currX = t.klt.x;
  			float currY = t.klt.y;
  
  			// track in reverse direction
  			tracker.setDescription(t.klt);
  			tracker.setImage(previousImage, previousDerivX, previousDerivY);
  			result = tracker.track(t.klt);
  			if( result != KltTrackFault.SUCCESS ) {
  				t.active = false;
  				continue;
  			}
  
  			// compute forward-backwards error
  			double errorForwardBackwards = UtilPoint2D_F32.distanceSq(prevX,prevY,t.klt.x,t.klt.y);
  
  			// put into lists for computing the median error
  			errorsFB[numTracksFB++] = errorForwardBackwards;
  
  			// discard if error is too large
  			if( errorForwardBackwards > maxErrorFB ) {
  				t.active = false;
  				continue;
  			}
  
  			// create data structure used for group motion estimation
  			AssociatedPair p = pairs.grow();
  			p.p1.set( prevX, prevY );
  			p.p2.set( currX, currY );
  
  			numTracksRemaining++;
  		}
  
  		// if the forward-backwards error is too large, give up
  		double medianFB = QuickSelect.select(errorsFB,numTracksFB/2,numTracksFB);
  
  //		System.out.println("Median tracking error FB: "+medianFB);
  
  		if( medianFB > maxErrorFB || numTracksRemaining < 4 )
  			return false;
  
  		return true;
  	}