changeset 156:d6df9fe7b12f refactors

Implement distance metric selection (euclidean or cosine)
author Chris Cannam
date Thu, 29 Jan 2015 10:25:47 +0000
parents 246de093f0f1
children d6c1556fadd0
files src/DistanceMetric.cpp src/DistanceMetric.h src/MatchVampPlugin.cpp
diffstat 3 files changed, 55 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/DistanceMetric.cpp	Fri Jan 23 09:20:04 2015 +0000
+++ b/src/DistanceMetric.cpp	Thu Jan 29 10:25:47 2015 +0000
@@ -39,10 +39,33 @@
 {
     double d = 0;
     double sum = 0;
+    double eps = 1e-16;
 
     int featureSize = f1.size();
     assert(int(f2.size()) == featureSize);
 
+    if (m_params.metric == Cosine) {
+
+        double num = 0, denom1 = 0, denom2 = 0;
+        
+        for (int i = 0; i < featureSize; ++i) {
+            num += f1[i] * f2[i];
+            denom1 += f1[i] * f1[i];
+            denom2 += f2[i] * f2[i];
+        }
+
+        d = 1.0 - (num / (eps + sqrt(denom1 * denom2)));
+
+        if (m_params.noise == AddNoise) {
+            d += 1e-2;
+        }
+        if (d > 1.0) d = 1.0;
+        
+        return d; // normalisation param ignored
+    }
+
+    // Euclidean
+    
     for (int i = 0; i < featureSize; i++) {
         d += fabs(f1[i] - f2[i]);
         sum += fabs(f1[i]) + fabs(f2[i]);
--- a/src/DistanceMetric.h	Fri Jan 23 09:20:04 2015 +0000
+++ b/src/DistanceMetric.h	Thu Jan 29 10:25:47 2015 +0000
@@ -22,6 +22,17 @@
 class DistanceMetric
 {
 public:
+    enum Metric {
+
+        /** Calculate the Euclidean distance between feature vectors. */
+        Euclidean,
+
+        /** Calculate the cosine distance between feature vectors. The
+         *  normalisation setting will be ignored as the result is
+         *  already magnitude-independent. */
+        Cosine,
+    };
+
     enum DistanceNormalisation {
             
         /** Do not normalise distance metrics */
@@ -35,7 +46,7 @@
          *  of the sum of the frames. */
         NormaliseDistanceToLogSum,
     };
-
+    
     enum NoiseAddition {
 
         /** Don't add noise. */
@@ -49,11 +60,12 @@
     struct Parameters {
 
         Parameters() :
+            metric(Euclidean),
             norm(NormaliseDistanceToLogSum),
             noise(AddNoise)
         {}
 
-        /** Normalisation for distance metrics. */
+        Metric metric;
         DistanceNormalisation norm;
         NoiseAddition noise;
     };
--- a/src/MatchVampPlugin.cpp	Fri Jan 23 09:20:04 2015 +0000
+++ b/src/MatchVampPlugin.cpp	Thu Jan 29 10:25:47 2015 +0000
@@ -215,6 +215,20 @@
     desc.isQuantized = false;
     list.push_back(desc);
 
+    desc.identifier = "metric";
+    desc.name = "Distance metric";
+    desc.description = "Metric for distance calculations.";
+    desc.minValue = 0;
+    desc.maxValue = 1;
+    desc.defaultValue = (int)m_defaultDParams.metric;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    desc.valueNames.clear();
+    desc.valueNames.push_back("Euclidean");
+    desc.valueNames.push_back("Cosine");
+    list.push_back(desc);
+    desc.valueNames.clear();
+
     desc.identifier = "noise";
     desc.name = "Mix in Noise";
     desc.description = "Whether to mix in a small constant white noise term when calculating feature distance. This can improve alignment against sources containing cleanly synthesised audio.";
@@ -293,6 +307,8 @@
         return m_smooth ? 1.0 : 0.0;
     } else if (name == "silencethreshold") {
         return m_fcParams.silenceThreshold;
+    } else if (name == "metric") {
+        return (int)m_dParams.metric;
     } else if (name == "noise") {
         return m_dParams.noise;
     }
@@ -323,6 +339,8 @@
         m_smooth = (value > 0.5);
     } else if (name == "silencethreshold") {
         m_fcParams.silenceThreshold = value;
+    } else if (name == "metric") {
+        m_dParams.metric = (DistanceMetric::Metric)(int(value + 0.1));
     } else if (name == "noise") {
         m_dParams.noise = (DistanceMetric::NoiseAddition)(int(value + 0.1));
     }