计算两个数组之间余弦相似度的正确方法?

时间:2015-05-22 19:02:20

标签: c++ arrays opencv mat cosine-similarity

我正在开发一个项目,可以检测两个输入图像(手写签名)的某些功能,并使用余弦相似性比较这两个功能。这里当我指两个输入图像时,一个是原始图像,另一个是重复图像。 假设我正在提取一个图像(原始图像)的15个这样的特征并将其存储在一个数组(Say,Array_ORG)中,并且其他图像的特征类似地存储在Array_DUP中。 现在,我试图计算这两个数组之间的余弦相似度。这些数组是双数据类型。

我列出了我遵循的两种方法:

1)手动计算余弦相似度:

main(){

for(int i=0;i<15;i++)
    sum_org += (Array_org[i]*Array_org[i]);
for(int i=0;i<15;i++)
    sum_dup += (Array_dup[i]*Array_dup[i]);
double magnitude = sqrt(sum_org +sum_dup );
double cosine_similarity = dot_product(Array_org, Array_dup, sizeof(Array_org)/sizeof(Array_org[0]))/magnitude;
}

double dot_product(double *a, double* b, size_t n){
double sum = 0;
    size_t i;

    for (i = 0; i < n; i++) {
            sum += a[i] * b[i];
    }

    return sum;
}

2)将值存储到Mat并调用点函数:

Mat A = Mat(1,15,CV_32FC1,&Array_org);
Mat B = Mat(1,15,CV_32FC1,&Array_dup);
double similarity = cal_theta(A,B);

double cal_theta(Mat A, Mat B){
double ab = A.dot(B);
double aa = A.dot(A);
double bb = B.dot(B);
return -ab / sqrt(aa*bb);
}

我已经读过余弦相似度值的范围从-1到1,-1表示两者相反,而1表示两者相等。但是第一个函数给出了1000的值,第二个函数给出了超过1的值。
请指导我哪个过程是正确的,为什么? 如果余弦相似度值大于1,我该如何推断相似性?

2 个答案:

答案 0 :(得分:10)

余弦相似度的正确定义是:

enter image description here

您的代码不计算分母,因此值是错误的。

double cosine_similarity(double *A, double *B, unsigned int Vector_Length)
{
    double dot = 0.0, denom_a = 0.0, denom_b = 0.0 ;
     for(unsigned int i = 0u; i < Vector_Length; ++i) {
        dot += A[i] * B[i] ;
        denom_a += A[i] * A[i] ;
        denom_b += B[i] * B[i] ;
    }
    return dot / (sqrt(denom_a) * sqrt(denom_b)) ;
}

答案 1 :(得分:0)

只需添加一种使用Opencv(C ++)计算特征向量的余弦相似度的方法:

float cosSim = f1.dot(f2) / (cv::norm(f1) * cv::norm(f2));

其中f1f2均为一维cv::Mat,大小为(1, xx)