
boofcv.abst.feature.tracker.DetectDescribeAssociate Maven / Gradle / Ivy
Go to download
BoofCV is an open source Java library for real-time computer vision and robotics applications.
/*
* Copyright (c) 2011-2013, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.abst.feature.tracker;
import boofcv.abst.feature.associate.AssociateDescription2D;
import boofcv.struct.feature.AssociatedIndex;
import boofcv.struct.feature.TupleDesc;
import boofcv.struct.image.ImageSingleBand;
import georegression.struct.point.Point2D_F64;
import org.ddogleg.struct.FastQueue;
import java.util.ArrayList;
import java.util.List;
/**
*
* Base class for detect-describe-associate type trackers. Tracker works by detecting features in each image,
* computing a descriptor for each feature, then associating the features together.
*
*
* @author Peter Abeles
*/
public class DetectDescribeAssociate
implements PointTracker {
// associates features between two images together
protected AssociateDescription2D associate;
// Detects features and manages descriptions
protected DdaFeatureManager manager;
// location of interest points
protected FastQueue locDst = new FastQueue(10,Point2D_F64.class,false);
protected FastQueue locSrc = new FastQueue(10,Point2D_F64.class,true);
// description of interest points
protected FastQueue featSrc;
protected FastQueue featDst;
// all tracks
protected List tracksAll = new ArrayList();
// recently associated tracks
protected List tracksActive = new ArrayList();
// tracks not matched to any recent features
protected List tracksInactive = new ArrayList();
// tracks dropped by the tracker
protected List tracksDropped = new ArrayList();
// tracks recently spawned
protected List tracksNew = new ArrayList();
// previously declared tracks which are being recycled
protected List unused = new ArrayList();
// Data returned by associate
protected FastQueue matches;
// number of features created. Used to assign unique IDs
protected long featureID = 0;
// should it update the feature description after each association?
boolean updateDescription;
// indicates if a feature was associated or not
protected boolean isAssociated[] = new boolean[1];
/**
* Configures tracker
*
* @param associate Association
* @param updateDescription If true then the feature description will be updated after each image.
* Typically this should be false.
*/
public DetectDescribeAssociate(DdaFeatureManager manager,
final AssociateDescription2D associate,
final boolean updateDescription ) {
this.manager = manager;
this.associate = associate;
this.updateDescription = updateDescription;
featSrc = new FastQueue(10,manager.getDescriptionType(),false);
featDst = new FastQueue(10,manager.getDescriptionType(),false);
}
protected DetectDescribeAssociate() {
}
public boolean isUpdateDescription() {
return updateDescription;
}
/**
* If a feature is associated should the description be updated with the latest observation?
*/
public void setUpdateDescription(boolean updateDescription) {
this.updateDescription = updateDescription;
}
@Override
public void reset() {
dropAllTracks();
featureID = 0;
featDst.reset();
locDst.reset();
matches = null;
}
@Override
public void process( I input ) {
tracksActive.clear();
tracksInactive.clear();
tracksDropped.clear();
tracksNew.clear();
featDst.reset();
locDst.reset();
manager.detectFeatures(input, locDst, featDst);
// skip if there are no features
if( !tracksAll.isEmpty() ) {
performTracking();
// add unassociated to the list
for( int i = 0; i < tracksAll.size(); i++ ) {
if( !isAssociated[i] )
tracksInactive.add(tracksAll.get(i));
}
// clean up
featSrc.reset();
locSrc.reset();
}
}
protected void performTracking() {
// create source list
putIntoSrcList();
// associate features together
associate.setSource(locSrc, featSrc);
associate.setDestination(locDst, featDst);
associate.associate();
// used in spawn tracks. if null then no tracking data is assumed
matches = associate.getMatches();
// Update the track state using association information
updateTrackState(matches);
}
/**
* Put existing tracks into source list for association
*/
protected void putIntoSrcList() {
// make sure isAssociated is large enough
if( isAssociated.length < tracksAll.size() ) {
isAssociated = new boolean[ tracksAll.size() ];
}
featSrc.reset();
locSrc.reset();
for( int i = 0; i < tracksAll.size(); i++ ) {
PointTrack t = tracksAll.get(i);
Desc desc = t.getDescription();
featSrc.add(desc);
locSrc.add(t);
isAssociated[i] = false;
}
}
/**
* Update each track's location and description (if configured to do so) mark tracks as being associated.
*/
protected void updateTrackState( FastQueue matches ) {
// update tracks
for( int i = 0; i < matches.size; i++ ) {
AssociatedIndex indexes = matches.data[i];
PointTrack track = tracksAll.get(indexes.src);
Point2D_F64 loc = locDst.data[indexes.dst];
track.set(loc.x, loc.y);
tracksActive.add(track);
// update the description
if(updateDescription) {
((Desc)track.getDescription()).setTo(featDst.get(indexes.dst));
}
isAssociated[indexes.src] = true;
}
}
/**
* Takes the current crop of detected features and makes them the keyframe
*/
@Override
public void spawnTracks() {
// setup data structures
if( isAssociated.length < featDst.size ) {
isAssociated = new boolean[ featDst.size ];
}
// see which features are associated in the dst list
for( int i = 0; i < featDst.size; i++ ) {
isAssociated[i] = false;
}
if( matches != null ) {
for( int i = 0; i < matches.size; i++ ) {
isAssociated[matches.data[i].dst] = true;
}
}
// create new tracks from latest unassociated detected features
for( int i = 0; i < featDst.size; i++ ) {
if( isAssociated[i] )
continue;
Point2D_F64 loc = locDst.get(i);
addNewTrack(loc.x,loc.y,featDst.get(i));
}
}
/**
* Adds a new track given its location and description
*/
protected PointTrack addNewTrack( double x , double y , Desc desc ) {
PointTrack p = getUnused();
p.set(x, y);
((Desc)p.getDescription()).setTo(desc);
if( checkValidSpawn(p) ) {
p.featureId = featureID++;
tracksNew.add(p);
tracksActive.add(p);
tracksAll.add(p);
return p;
} else {
unused.add(p);
return null;
}
}
/**
* Returns true if a new track can be spawned here. Intended to be overloaded
*/
protected boolean checkValidSpawn( PointTrack p ) {
return true;
}
/**
* Returns an unused track. If there are no unused tracks then it creates a ne one.
*/
protected PointTrack getUnused() {
PointTrack p;
if( unused.size() > 0 ) {
p = unused.remove( unused.size()-1 );
} else {
p = new PointTrack();
p.setDescription(manager.createDescription());
}
return p;
}
@Override
public void dropAllTracks() {
unused.addAll(tracksAll);
tracksActive.clear();
tracksInactive.clear();
tracksAll.clear();
tracksNew.clear();
}
/**
* Remove from active list and mark so that it is dropped in the next cycle
*
* @param track The track which is to be dropped
*/
@Override
public boolean dropTrack(PointTrack track) {
if( !tracksAll.remove(track) )
return false;
// the track may or may not be in the active list
tracksActive.remove(track);
tracksInactive.remove(track);
// it must be in the all list
// recycle the data
unused.add(track);
return true;
}
@Override
public List getActiveTracks( List list ) {
if( list == null )
list = new ArrayList();
list.addAll(tracksActive);
return list;
}
@Override
public List getDroppedTracks( List list ) {
if( list == null )
list = new ArrayList();
list.addAll(tracksDropped);
return list;
}
@Override
public List getNewTracks( List list ) {
if( list == null )
list = new ArrayList();
list.addAll(tracksNew);
return list;
}
@Override
public List getAllTracks( List list ) {
if( list == null )
list = new ArrayList();
list.addAll(tracksAll);
return list;
}
@Override
public List getInactiveTracks(List list) {
if( list == null )
list = new ArrayList();
list.addAll(tracksInactive);
return list;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy