/* * Copyright (c) 2011-2015, 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.descriptor; import boofcv.struct.feature.*; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestDescriptorDistance { Random rand = new Random(234); @Test public void euclidean_F64() { TupleDesc_F64 a = new TupleDesc_F64(5); TupleDesc_F64 b = new TupleDesc_F64(5); a.value=new double[]{1,2,3,4,5}; b.value=new double[]{2,-1,7,-8,10}; assertEquals(13.964, DescriptorDistance.euclidean(a, b), 1e-2); } @Test public void euclideanSq_F64() { TupleDesc_F64 a = new TupleDesc_F64(5); TupleDesc_F64 b = new TupleDesc_F64(5); a.value=new double[]{1,2,3,4,5}; b.value=new double[]{2,-1,7,-8,10}; assertEquals(195, DescriptorDistance.euclideanSq(a, b), 1e-4); } @Test public void euclideanSq_F32() { TupleDesc_F32 a = new TupleDesc_F32(5); TupleDesc_F32 b = new TupleDesc_F32(5); a.value=new float[]{1,2,3,4,5}; b.value=new float[]{2,-1,7,-8,10}; assertEquals(195, DescriptorDistance.euclideanSq(a, b), 1e-4); } @Test public void correlation() { TupleDesc_F64 a = new TupleDesc_F64(5); TupleDesc_F64 b = new TupleDesc_F64(5); a.value=new double[]{1,2,3,4,5}; b.value=new double[]{2,-1,7,-8,10}; assertEquals(39, DescriptorDistance.correlation(a, b), 1e-2); } @Test public void ncc() { NccFeature a = new NccFeature(5); NccFeature b = new NccFeature(5); a.sigma = 12; b.sigma = 7; a.value=new double[]{1,2,3,4,5}; b.value=new double[]{2,-1,7,-8,10}; assertEquals(0.46429/5.0,DescriptorDistance.ncc(a, b),1e-2); } /** * When a correctly computed NCC descriptor is compared against itself the distance should be one */ @Test public void ncc_self_distance() { NccFeature a = new NccFeature(5); for( int i = 0; i < a.value.length; i++ ) a.value[i] = i*i; double mean = 0; for( int i = 0; i < a.value.length; i++ ) mean += a.value[i]; mean /= a.size(); double sigma = 0; for( int i = 0; i < a.value.length; i++ ) { double d = a.value[i] -= mean; sigma += d*d; } sigma /= a.size(); a.mean = mean; a.sigma = Math.sqrt(sigma); assertEquals(1,DescriptorDistance.ncc(a, a),1e-2); } @Test public void sad_U8() { TupleDesc_U8 a = new TupleDesc_U8(5); TupleDesc_U8 b = new TupleDesc_U8(5); a.value=new byte[]{1,2,3,4,(byte)200}; b.value=new byte[]{(byte)245,2,6,3,6}; assertEquals(442, DescriptorDistance.sad(a, b), 1e-2); } @Test public void sad_S8() { TupleDesc_S8 a = new TupleDesc_S8(5); TupleDesc_S8 b = new TupleDesc_S8(5); a.value=new byte[]{1,2,3,4,5}; b.value=new byte[]{-2,2,-3,3,6}; assertEquals(11, DescriptorDistance.sad(a, b), 1e-2); } @Test public void sad_F32() { TupleDesc_F32 a = new TupleDesc_F32(5); TupleDesc_F32 b = new TupleDesc_F32(5); a.value=new float[]{ 0.1f ,2 ,3 ,-4.9f ,5}; b.value=new float[]{-1 ,45.5f ,6 ,3 ,6.01f}; assertEquals(56.51,DescriptorDistance.sad(a, b),1e-2); } @Test public void sad_F64() { TupleDesc_F64 a = new TupleDesc_F64(5); TupleDesc_F64 b = new TupleDesc_F64(5); a.value=new double[]{ 0.1 ,2 ,3 ,-4.9 ,5}; b.value=new double[]{-1 ,45.5 ,6 ,3 ,6.01}; assertEquals(56.51,DescriptorDistance.sad(a, b),1e-2); } @Test public void hamming_I32() { TupleDesc_B a = new TupleDesc_B(512); TupleDesc_B b = new TupleDesc_B(512); for( int numTries = 0; numTries < 20; numTries++ ) { for( int i = 0; i < a.data.length; i++ ) { a.data[i] = rand.nextInt(); b.data[i] = rand.nextInt(); } assertEquals(hamming(a,b),DescriptorDistance.hamming(a, b),1e-4); } } @Test public void hamming_int() { assertEquals(0,DescriptorDistance.hamming(0)); assertEquals(1,DescriptorDistance.hamming(0x0800)); assertEquals(1,DescriptorDistance.hamming(0x0001)); assertEquals(2,DescriptorDistance.hamming(0x0101)); assertEquals(4,DescriptorDistance.hamming(0x000F)); assertEquals(8,DescriptorDistance.hamming(0xF000000F)); } private int hamming( TupleDesc_B a, TupleDesc_B b) { int ret = 0; for( int i = 0; i < a.data.length; i++ ) { ret += hamming(a.data[i],b.data[i]); } return ret; } public static int hamming( int a , int b ) { int distance = 0; // see which bits are different int val = a ^ b; // brute force hamming distance if( (val & 0x00000001) != 0) distance++; if( (val & 0x00000002) != 0) distance++; if( (val & 0x00000004) != 0) distance++; if( (val & 0x00000008) != 0) distance++; if( (val & 0x00000010) != 0) distance++; if( (val & 0x00000020) != 0) distance++; if( (val & 0x00000040) != 0) distance++; if( (val & 0x00000080) != 0) distance++; if( (val & 0x00000100) != 0) distance++; if( (val & 0x00000200) != 0) distance++; if( (val & 0x00000400) != 0) distance++; if( (val & 0x00000800) != 0) distance++; if( (val & 0x00001000) != 0) distance++; if( (val & 0x00002000) != 0) distance++; if( (val & 0x00004000) != 0) distance++; if( (val & 0x00008000) != 0) distance++; if( (val & 0x00010000) != 0) distance++; if( (val & 0x00020000) != 0) distance++; if( (val & 0x00040000) != 0) distance++; if( (val & 0x00080000) != 0) distance++; if( (val & 0x00100000) != 0) distance++; if( (val & 0x00200000) != 0) distance++; if( (val & 0x00400000) != 0) distance++; if( (val & 0x00800000) != 0) distance++; if( (val & 0x01000000) != 0) distance++; if( (val & 0x02000000) != 0) distance++; if( (val & 0x04000000) != 0) distance++; if( (val & 0x08000000) != 0) distance++; if( (val & 0x10000000) != 0) distance++; if( (val & 0x20000000) != 0) distance++; if( (val & 0x40000000) != 0) distance++; if( (val & 0x80000000) != 0) distance++; return distance; } }