private void ShowFingerprints(SubFingerprintLookupEntry sfp1, SubFingerprintLookupEntry sfp2) { Fingerprint fp1 = store.GetFingerprint(sfp1); Fingerprint fp2 = store.GetFingerprint(sfp2); Fingerprint fpDifference = fp1.Difference(fp2); fingerprintView1.Fingerprint = fp1; fingerprintView2.Fingerprint = fp2; fingerprintView3.Fingerprint = fpDifference; berLabel.Content = Fingerprint.CalculateBER(fp1, fp2); }
public List <Match> FindMatchesFromExternalSubFingerprints(AudioTrack audioTrack, List <SubFingerprintHash> hashes) { if (hashes.Count < this.fingerprintSize) { throw new ArgumentException(String.Format( "Hash list is too short, cannot build fingerprints (given {0}, required at least {1})", hashes.Count, this.fingerprintSize)); } var matches = new List <Match>(); int collisionCount = 0; for (int i = 0; i < hashes.Count; i++) { List <SubFingerprintLookupEntry> collisions = this.collisionMap.GetValues(hashes[i]); foreach (var collision in collisions) { collisionCount++; // The indices at which the fingerprints begin within the hash lists int externalIndex = i; int internalIndex = collision.Index; // The hash lists var externalHashes = hashes; var internalHashes = store[collision.AudioTrack]; // The lengths of the hash lists (the number of subfingerprints/hashes) int externalHashCount = externalHashes.Count; int internalHashCount = internalHashes.Count; // The overflow if directly taken at the indices int externalOverflow = this.fingerprintSize - (externalHashCount - externalIndex); int internalOverflow = this.fingerprintSize - (internalHashCount - internalIndex); // The bigger of both overflows is the value by which we need to shift the sampling to the left int leftShift = Math.Max(externalOverflow, internalOverflow); // Check if we need to do a shift // If the left shift is > 0, we need to shift the fingerprints to the left // if the shift is <= 0, the fingerprints can be directly sampled from the hash lists // (the negative value is their distance to the right border) if (leftShift > 0) { // We need to shift the fingerprints to the left because one or both would otherwise overflow the right border externalIndex -= leftShift; internalIndex -= leftShift; // Before we take the fingerprints, we need to check if that is even possible or if a fingerprint // would then overflow the left border if (externalIndex < 0 || internalIndex < 0) { // A fingerprint would now overflow the left border, so for this collision it is not possible // to take fingerprints that we can compare // Skip to the next collision continue; } } // TODO detect duplicate matching attempts and skip them to minimize matching cost // A matching attempt can be described as the tuple (internalAudioTrack, externalIndex, internalIndex) // Take the fingerprints that we want to compare Fingerprint externalFingerprint = new Fingerprint(externalHashes, externalIndex, this.fingerprintSize); // We don't use GetFingerprint here because that function shifts the fingerprint left for an unknown offset // if taken at the right border Fingerprint internalFingerprint = new Fingerprint(internalHashes, internalIndex, this.fingerprintSize); // Calculate the bit error rate between both fingerprints float bitErrorRate = Fingerprint.CalculateBER(externalFingerprint, internalFingerprint); Console.WriteLine(String.Format("{0} <> {1} => {2}", externalIndex, internalIndex, bitErrorRate)); if (bitErrorRate < threshold) { matches.Add(new Match { Similarity = 1 - bitErrorRate, Track1 = collision.AudioTrack, Track1Time = SubFingerprintIndexToTimeSpan(internalIndex), Track2 = audioTrack, Track2Time = SubFingerprintIndexToTimeSpan(externalIndex), Source = matchSourceName, }); } } } Console.WriteLine(String.Format("{0} collisions, {1} matches", collisionCount, matches.Count)); return(matches); }