在实际工作中,协方差作为数据的重要统计特征,我们经常会用到。最近在用到opencv_py的cv2.calcCovarMatrix求数据的协方差时就踩了一个小坑,特记录一下。例如,我要求下面数据(每一行是某一图像的CrCb值,一共有几万个数据对,也就是几万个样本)的协方差,数据名字label_pixVale。
…………… ……………
第一时间想到用了用opencv自带的函数:
covar, means = cv2.calcCovarMatrix(label_pixVale, mean=mean, flags=cv2.COVAR_ROWS |cv2.COVAR_SCALE)
这个用法貌似没错,但是运行就报OutOfMemoryError的错误,COVAR_ROWS参数已经指明样本是作为行是没错的。虽然我的数据比较多,但是维度只有2,怎么会溢出呢?
因为只有两个维度,比较简单,于是自己写了下协方差的计算:
xx = 0
yy = 0
xy = 0
means = np.mean(np.array(label_pixVale), axis=0)
num = label_pixVale.shape[0]
for i in range(num):
xx += (label_pixVale[i][0] - means[0]) * (label_pixVale[i][0] - means[0])
yy += (label_pixVale[i][1] - means[1]) * (label_pixVale[i][1] - means[1])
xy += (label_pixVale[i][0] - means[0]) * (label_pixVale[i][1] - means[1])
xx /= (num -1)
yy /= (num -1)
xy /= (num -1)
没有内存溢出的情况。
于是找答案,查看opencv文档(opencv2.3.2):
红色框中,CV_COVAR_SCRAMBLED 和CV_COVAR_NORMAL必须指定一个,于是用这样设置:
covar, means = cv2.calcCovarMatrix(label_pixVale, mean=means, flags=cv2.COVAR_ROWS |cv2.COVAR_SCALE |cv2.COVAR_NORMAL)
这样运行就正确了,与手写的结果基本一致,但是还有一点点不一样,从CV_COVAR_SCALE参数说明可以看到,opencv归一是除以样本总数,然而协方差计算公式应该是除以(样本总数-1)。