颜色直方图+余弦相似度 c++opencv实现

原理部分来自阮一峰博客

http://www.ruanyifeng.com/blog/2013/03/similar_image_search_part_ii.html

颜色分布法:

每张图片都可以生成颜色分布的直方图(color histogram)。如果两张图片的直方图很接近,就可以认为它们很相似。

任何一种颜色都是由红绿蓝三原色(RGB)构成的,所以上图共有4张直方图(三原色直方图 + 最后合成的直方图)。

如果每种原色都可以取256个值,那么整个颜色空间共有1600万种颜色(256的三次方)。针对这1600万种颜色比较直方图,计算量实在太大了,因此需要采用简化方法。可以将0~255分成四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝分别有4个区,总共可以构成64种组合(4的3次方)。

任何一种颜色必然属于这64种组合中的一种,这样就可以统计每一种组合包含的像素数量。

上图是某张图片的颜色分布表,将表中最后一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, ..., 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫"指纹"。

于是,寻找相似图片就变成了找出与其最相似的向量。这可以用皮尔逊相关系数或者余弦相似度算出。

实现代码如下:

颜色直方图+余弦相似度 c++opencv实现_第1张图片               颜色直方图+余弦相似度 c++opencv实现_第2张图片

#include 
#include 
#include 
#include 
#include 
using namespace std;
using namespace cv;
void getRGBvector(const Mat&src, vector& count)//得到64维向量
{
	int nRows = src.rows,nCols = src.cols * src.channels();
	const uchar* p;
	for (int i = 0; i < nRows; ++i)
	{
		p = src.ptr(i);
		for (int j = 0; j < nCols; j += 3)
		{
			int r = int(p[j])/64;    
			int g = int(p[j + 1])/64;
			int b = int(p[j + 2])/64;
			count[r * 16 + g * 4 + b]++;
		}
	}
}
double getVectorLength(vector &vec)
{
	long long res = 0;
	for (int i = 0; i < vec.size(); i++)
 		res += vec[i] * vec[i];
 	return sqrt(res);
}
double getcos(vector &count1, vector &count2)
{
	double len1 = getVectorLength(count1);
	double len2 = getVectorLength(count2);
	assert(len1 != 0 && len2 != 0);
	long long sum = 0;
	for (int i = 0; i < count1.size(); i++)
		sum += count1[i] * count2[i];
	return (double)sum / len1 / len2 >0 ? (double)sum / len1 / len2:0;
}
double getsimilarity(const Mat&src1, const Mat&src2)
{
	vector count1(64), count2(64);
	getRGBvector(src1, count1);
	getRGBvector(src2, count2);
	double res = getcos(count1, count2);
	return res;
}
int main()
{
	Mat src1 = imread("晚霞1.jpg",1),src2 = imread("晚霞2.jpg", 1);
	imshow("src", src1),imshow("src", src2);
	double res = getsimilarity(src1,src2);
	cout << res << endl;
	waitKey(0);

}

你可能感兴趣的:(c++,opencv)