/* * Copyright (c) 2011-2016, 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.feature.associate; import boofcv.abst.feature.associate.AssociateDescription; import boofcv.abst.feature.associate.ScoreAssociateEuclidean_F64; import boofcv.abst.feature.associate.ScoreAssociation; import boofcv.factory.feature.associate.FactoryAssociation; import boofcv.struct.feature.AssociatedIndex; import boofcv.struct.feature.BrightFeature; import boofcv.struct.feature.TupleDesc_F64; import org.ddogleg.struct.FastQueue; import org.ddogleg.struct.GrowQueue_I32; import org.junit.Test; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestAssociateSurfBasic { AssociateSurfBasic alg = createAlg(); /** * Two features with different laplacian signs should never be associated */ @Test public void checkAssociateByIntensity() { FastQueue<BrightFeature> src = new FastQueue<>(10, BrightFeature.class, false); FastQueue<BrightFeature> dst = new FastQueue<>(10, BrightFeature.class, false); src.add( createDesc(true,10)); dst.add( createDesc(true,0)); dst.add( createDesc(false,10)); alg.setSrc(src); alg.setDst(dst); alg.associate(); FastQueue<AssociatedIndex> matches = alg.getMatches(); assertEquals(1,matches.size()); // it should match with the first one, even though the second has a better feature set assertEquals(0,matches.get(0).dst); } @Test public void basicAssociation() { FastQueue<BrightFeature> src = new FastQueue<>(10, BrightFeature.class, false); FastQueue<BrightFeature> dst = new FastQueue<>(10, BrightFeature.class, false); // create a list where some should be matched and others not src.add( createDesc(true,10)); src.add( createDesc(true,12)); src.add( createDesc(false,5)); src.add( createDesc(false,2344)); src.add( createDesc(false,1000)); dst.add( createDesc(true,0)); dst.add( createDesc(true,10.1)); dst.add( createDesc(true,13)); dst.add( createDesc(false,0.1)); dst.add( createDesc(false,7)); alg.setSrc(src); alg.setDst(dst); alg.associate(); FastQueue<AssociatedIndex> matches = alg.getMatches(); assertEquals(3,matches.size()); assertTrue(matches.get(0).fitScore != 0); assertEquals(0,matches.get(0).src); assertEquals(1,matches.get(0).dst); assertTrue(matches.get(1).fitScore != 0); assertEquals(1,matches.get(1).src); assertEquals(2,matches.get(1).dst); assertTrue(matches.get(2).fitScore != 0); assertEquals(2,matches.get(2).src); assertEquals(4,matches.get(2).dst); // see if the expected number of features are in the unassociated list GrowQueue_I32 unassoc = alg.unassociatedSrc; assertEquals(2,unassoc.size); // make sure none of the unassociated are contained in the associated list for( int i = 0; i < unassoc.size; i++ ) { int index = unassoc.data[i]; for( int j = 0; j < matches.size(); j++ ) { if( matches.get(j).src == index ) fail("match found"); } } } private AssociateSurfBasic createAlg() { ScoreAssociation<TupleDesc_F64> score = new ScoreAssociateEuclidean_F64(); AssociateDescription<TupleDesc_F64> assoc = FactoryAssociation.greedy(score, 20, true); return new AssociateSurfBasic(assoc); } private BrightFeature createDesc(boolean laplace , double value ) { BrightFeature ret = new BrightFeature(64); ret.white = laplace; ret.value[0] = value; return ret; } @Test public void checkUnassociated() { FastQueue<BrightFeature> src = new FastQueue<>(10, BrightFeature.class, false); FastQueue<BrightFeature> dst = new FastQueue<>(10, BrightFeature.class, false); src.add( createDesc(true,10)); src.add( createDesc(true,12)); src.add( createDesc(false,5)); dst.add( createDesc(true,0)); dst.add( createDesc(true,10.1)); dst.add( createDesc(true,13)); dst.add( createDesc(false,0.1)); dst.add( createDesc(false,7)); ScoreAssociation<TupleDesc_F64> score = new ScoreAssociateEuclidean_F64(); AssociateDescription<TupleDesc_F64> assoc = FactoryAssociation.greedy(score, 20, true); AssociateSurfBasic alg = new AssociateSurfBasic(assoc); alg.setSrc(src); alg.setDst(dst); alg.associate(); FastQueue<AssociatedIndex> matches = alg.getMatches(); } /** * Shouldn't crash in this case. just do nothing and clear previous results */ @Test public void handleEmptyLists() { // Initialize it with a successful association FastQueue<BrightFeature> src = new FastQueue<>(10, BrightFeature.class, false); FastQueue<BrightFeature> dst = new FastQueue<>(10, BrightFeature.class, false); src.add( createDesc(true,10)); src.add( createDesc(true,12)); src.add( createDesc(false,5)); dst.add( createDesc(true,10)); dst.add( createDesc(true,12)); dst.add( createDesc(false,5)); AssociateSurfBasic alg = createAlg(); alg.setSrc(src); alg.setDst(dst); alg.associate(); assertTrue( alg.getMatches().size() > 0 ); // now have the src list be empty alg.setSrc(new FastQueue<>(BrightFeature.class,false)); alg.setDst(dst); alg.associate(); assertTrue( alg.getMatches().size() == 0 ); // match stuff up again alg.setSrc(src); alg.setDst(dst); alg.associate(); assertTrue( alg.getMatches().size() > 0 ); // dst list is empty now alg.setSrc(src); alg.setDst(new FastQueue<>(BrightFeature.class,false)); alg.associate(); assertTrue( alg.getMatches().size() == 0 ); } }