/*
* Copyright (C) 2012 Jacquet Wong
*
* 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 com.musicg.fingerprint;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import com.musicg.math.rank.MapRank;
import com.musicg.math.rank.MapRankInteger;
/**
* Compute the similarity of two fingerprints
*
* @author jacquet
*
*/
public class FingerprintSimilarityComputer{
private FingerprintSimilarity fingerprintSimilarity;
byte[] fingerprint1, fingerprint2;
/**
* Constructor, ready to compute the similarity of two fingerprints
*
* @param fingerprint1
* @param fingerprint2
*/
public FingerprintSimilarityComputer(byte[] fingerprint1, byte[] fingerprint2){
this.fingerprint1=fingerprint1;
this.fingerprint2=fingerprint2;
fingerprintSimilarity=new FingerprintSimilarity();
}
/**
* Get fingerprint similarity of inout fingerprints
*
* @return fingerprint similarity object
*/
public FingerprintSimilarity getFingerprintsSimilarity(){
HashMap<Integer,Integer> offset_Score_Table=new HashMap<Integer,Integer>(); // offset_Score_Table<offset,count>
int numFrames=0;
float score=0;
int mostSimilarFramePosition=Integer.MIN_VALUE;
// one frame may contain several points, use the shorter one be the denominator
if (fingerprint1.length>fingerprint2.length){
numFrames=FingerprintManager.getNumFrames(fingerprint2);
}
else{
numFrames=FingerprintManager.getNumFrames(fingerprint1);
}
// get the pairs
PairManager pairManager=new PairManager();
HashMap<Integer,List<Integer>> this_Pair_PositionList_Table=pairManager.getPair_PositionList_Table(fingerprint1);
HashMap<Integer,List<Integer>> compareWave_Pair_PositionList_Table=pairManager.getPair_PositionList_Table(fingerprint2);
Iterator<Integer> compareWaveHashNumberIterator=compareWave_Pair_PositionList_Table.keySet().iterator();
while (compareWaveHashNumberIterator.hasNext()){
int compareWaveHashNumber=compareWaveHashNumberIterator.next();
// if the compareWaveHashNumber doesn't exist in both tables, no need to compare
if (!this_Pair_PositionList_Table.containsKey(compareWaveHashNumber)
|| !compareWave_Pair_PositionList_Table.containsKey(compareWaveHashNumber)){
continue;
}
// for each compare hash number, get the positions
List<Integer> wavePositionList=this_Pair_PositionList_Table.get(compareWaveHashNumber);
List<Integer> compareWavePositionList=compareWave_Pair_PositionList_Table.get(compareWaveHashNumber);
Iterator<Integer> wavePositionListIterator=wavePositionList.iterator();
while (wavePositionListIterator.hasNext()){
int thisPosition=wavePositionListIterator.next();
Iterator<Integer> compareWavePositionListIterator=compareWavePositionList.iterator();
while (compareWavePositionListIterator.hasNext()){
int compareWavePosition=compareWavePositionListIterator.next();
int offset=thisPosition-compareWavePosition;
if (offset_Score_Table.containsKey(offset)){
offset_Score_Table.put(offset, offset_Score_Table.get(offset)+1);
}
else{
offset_Score_Table.put(offset, 1);
}
}
}
}
// map rank
MapRank mapRank=new MapRankInteger(offset_Score_Table,false);
// get the most similar positions and scores
List<Integer> orderedKeyList=mapRank.getOrderedKeyList(100, true);
if (orderedKeyList.size()>0){
int key=orderedKeyList.get(0);
// get the highest score position
if (mostSimilarFramePosition==Integer.MIN_VALUE){
mostSimilarFramePosition=key;
score=offset_Score_Table.get(key);
// accumulate the scores from neighbours
if (offset_Score_Table.containsKey(key-1)){
score+=offset_Score_Table.get(key-1)/2;
}
if (offset_Score_Table.containsKey(key+1)){
score+=offset_Score_Table.get(key+1)/2;
}
}
}
/*
Iterator<Integer> orderedKeyListIterator=orderedKeyList.iterator();
while (orderedKeyListIterator.hasNext()){
int offset=orderedKeyListIterator.next();
System.out.println(offset+": "+offset_Score_Table.get(offset));
}
*/
score/=numFrames;
float similarity=score;
// similarity >1 means in average there is at least one match in every frame
if (similarity>1){
similarity=1;
}
fingerprintSimilarity.setMostSimilarFramePosition(mostSimilarFramePosition);
fingerprintSimilarity.setScore(score);
fingerprintSimilarity.setSimilarity(similarity);
return fingerprintSimilarity;
}
}