/* * 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.alg.tracker.klt; import boofcv.alg.filter.derivative.GradientSobel; import boofcv.alg.misc.ImageMiscOps; import boofcv.core.image.border.BorderIndex1D_Extend; import boofcv.core.image.border.ImageBorder1D_F32; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestPyramidKltTracker extends PyramidKltTestBase { @Before public void setup() { super.setup(); } private void setTargetLocation( int x , int y ) { ImageMiscOps.fillUniform(image,rand,0,1); ImageMiscOps.fillRectangle(image,100,cornerX,cornerY,20,20); pyramid.process(image); for( int i = 0; i < pyramid.getNumLayers(); i++ ) { GradientSobel.process(pyramid.getLayer(i),derivX[i],derivY[i],new ImageBorder1D_F32(BorderIndex1D_Extend.class)); } } /** * Test set description when the image is fully inside the image for all the pyramid layers */ @Test public void setDescription() { // tell it to generate a feature inside directly on a pixel PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),featureReadius); feature.setPosition(25,20); tracker.setImage(pyramid,derivX,derivY); assertTrue(tracker.setDescription(feature)); // all the layers should have been set for( int i = 0; i < pyramid.getNumLayers(); i++ ) { assertTrue( feature.desc[i].Gxx != 0 ); } } /** * Test set description when a feature partially inside and outside of the image at all levels */ @Test public void setDescription_border() { // now tell it to set a description near the edge // only the first layer should be set PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),featureReadius); feature.setPosition(featureReadius-1,featureReadius-1); tracker.setImage(pyramid,derivX,derivY); assertTrue(tracker.setDescription(feature)); for( int i = 0; i < pyramid.getNumLayers(); i++ ) { assertTrue( feature.desc[i].x != 0 ); assertTrue( feature.desc[i].y != 0 ); assertTrue( feature.desc[i].Gxx != 0.0f ); } } /** * Test set description when a feature is completely outside the image */ @Test public void setDescription_outside() { // now tell it to set a description near the edge // only the first layer should be set PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),featureReadius); feature.setPosition(-featureReadius-1,-featureReadius-1); tracker.setImage(pyramid,derivX,derivY); assertFalse(tracker.setDescription(feature)); } /** * Test positive examples of tracking when there should be no fault at any point. * * Only a small offset easily done with a single layer tracker */ @Test public void track_smallOffset() { // set the feature right on the corner PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),featureReadius); feature.setPosition(cornerX,cornerY); tracker.setImage(pyramid,derivX,derivY); tracker.setDescription(feature); // now move the corner away from the feature feature.setPosition(cornerX-1.3f,cornerY+1.2f); // see if it moves back assertTrue( tracker.track(feature) == KltTrackFault.SUCCESS); assertEquals(cornerX,feature.x,0.2); assertEquals(cornerY,feature.y,0.2); } /** * Test positive examples of tracking when there should be no fault at any point. * * Larger offset which will require the pyramid approach */ @Test public void track_largeOffset() { // set the feature right on the corner PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),featureReadius); feature.setPosition(cornerX,cornerY); tracker.setImage(pyramid,derivX,derivY); tracker.setDescription(feature); // now move the corner away from the feature feature.setPosition(cornerX-5.4f,cornerY+5.3f); // see if it moves back assertTrue( tracker.track(feature) == KltTrackFault.SUCCESS); assertEquals(cornerX,feature.x,0.2); assertEquals(cornerY,feature.y,0.2); } /** * */ @Test public void track_border() { float targetX = width-featureReadius; float targetY = height-featureReadius-3; // set the feature right on the corner PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),featureReadius); feature.setPosition(targetX,targetY); tracker.setImage(pyramid,derivX,derivY); tracker.setDescription(feature); // start it outside the image, but still near its true position feature.setPosition(width-featureReadius+2,height-featureReadius-1); assertTrue( tracker.track(feature) == KltTrackFault.SUCCESS); assertEquals(targetX,feature.x,0.2); assertEquals(targetY,feature.y,0.2); } /** * See if a track out of bounds error is returned */ @Test public void track_OOB() { setTargetLocation(5*4+1,22); // set the feature right on the corner PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),4); feature.setPosition(21,22); tracker.setImage(pyramid,derivX,derivY); tracker.setDescription(feature); // put the feature out of bounds feature.setPosition(-20,-20); assertTrue( tracker.track(feature) == KltTrackFault.OUT_OF_BOUNDS); } /** * See if a track out of bounds error is returned */ @Test public void track_LargeError() { setTargetLocation(5*4+1,22); // set the feature right on the corner PyramidKltFeature feature = new PyramidKltFeature(pyramid.getNumLayers(),4); feature.setPosition(21,22); tracker.setImage(pyramid,derivX,derivY); tracker.setDescription(feature); // mess up the description so that it will produce a large error feature.desc[0].desc.set(0,0,1000); assertTrue( tracker.track(feature) == KltTrackFault.LARGE_ERROR); } }