目标:选出一个参考图像,找出一组图像中与参考图像最相似的图像。
相似图像检索:基于图像内容的相似度检索,可以利用两幅图像的直方图特征,评估两幅图像的直方图相似度,进而得到两幅图像的相似度。

第一步:直方图特征提取

函数calcHist用来计算图像直方图特征,函数原型如下:

void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )

例:计算一张彩色图像的直方图特征

//初始化数据
int histSize[3];//容器数(0~255),256项
float hranges[2];
const float* ranges[3];
int channels[3];

histSize[0]= histSize[1]= histSize[2]= 256;
hranges[0]= 0.0;// 像素的强度值范围
hranges[1]= 255.0;
ranges[0]= hranges;// 所用通道的数值范围相同
ranges[1]= hranges; 
ranges[2]= hranges; 
channels[0]= 0;// 三通道
channels[1]= 1; 
channels[2]= 2; 
//计算直方图特征
cv::calcHist(&image,    //图像
			1,			// 1张图片
			channels,	// 通道
			cv::Mat(),	// 掩码
			hist,		// 返回值,直方图特征类型为cv::MatND
			3,			// 3维
			histSize,	// 容器数量
			ranges		// 像素的强度值 范围
		);

第二步 比较两幅图像相似度

两幅图像的相似度,可以用他们的直方图特征的相似度来代替。
函数compareHist计算两个直方图的相似度,其函数原型如下,

double compareHist(const SparseMat& H1, const SparseMat& H2, int method)

其中method参数,可以指定测量方法,可选值如下:

CV_COMP_CORREL Correlation
CV_COMP_CHISQR Chi-Square
CV_COMP_INTERSECT Intersection
CV_COMP_BHATTACHARYYA Bhattacharyya distance
CV_COMP_HELLINGER Synonym for CV_COMP_BHATTACHARYYA

例:计算两个直方图的相似度。

double similar=cv::compareHist(refHist, inputHist, CV_COMP_INTERSECT);

similar的值越大,相似度越高。

第三步 相似图像检索

通过前两步得到两幅图像的相似度,我们便可以进行相似图像检索,找出与参考图像最相似的图像。其代码如下:
imagecompare.h

#ifndef IMAGECOMPARE_H
#define IMAGECOMPARE_H
#include"colorhistogram.h"

class ImageCompare
{
private:
	//参考图像
	cv::Mat reference;
	//检测图像
	cv::Mat input;
	//直方图数据
	cv::MatND refHist;
	cv::MatND inputHist;
	ColorHistogram h;
	//减色变量
	int div;
public:
	ImageCompare() :div(32){}
	void setColorReduction(int factor)
	{
		div = factor;
	}
	int getColorRedutction()const
	{
		return div;
	}
	//设置参考图像
	void setRerenceImage(const cv::Mat& image)
	{
		reference = image;
		refHist = h.getHistogram(image);
		//cv::normalize(refHist, refHist);
	}
	//比较两幅图像相似度
	double compare(const cv::Mat &image)
	{
		input = image;
		inputHist = h.getHistogram(image);
		//cv::normalize(inputHist, inputHist);
		return cv::compareHist(refHist, inputHist, CV_COMP_INTERSECT);
	}
};
#endif

colorhistogram.h

#ifndef COLHISTOGRAM
#define COLHISTOGRAM

#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include<opencv2\highgui\highgui.hpp>

class ColorHistogram {

  private:

    int histSize[3];
	float hranges[2];
    const float* ranges[3];
    int channels[3];

  public:

	ColorHistogram() {

		//初始化数据
		histSize[0]= histSize[1]= histSize[2]= 256;
		hranges[0]= 0.0;    // 像素的强度值范围
		hranges[1]= 255.0;
		ranges[0]= hranges; // 所用通道的数值范围相同
		ranges[1]= hranges; 
		ranges[2]= hranges; 
		channels[0]= 0;		// 三通道
		channels[1]= 1; 
		channels[2]= 2; 
	}
	
	// 计算直方图
	cv::MatND getHistogram(const cv::Mat &image) {

		cv::MatND hist;

		// 彩色直方图
		hranges[0]= 0.0;    
		hranges[1]= 255.0;
		channels[0]= 0;		
		channels[1]= 1; 
		channels[2]= 2; 

		// 计算直方图
		cv::calcHist(&image, 
			1,			// 1张图片
			channels,	// 通道
			cv::Mat(),	// 掩码
			hist,		// 直方图
			3,			// 3维
			histSize,	// 容器数量
			ranges		// 像素的强度值 范围
		);

		return hist;
	}

};


#endif

源.cpp

#include"imagecompare.h"
#include<iostream>
int main()
{
	//类对象
	ImageCompare h;
	//参考图像
	cv::Mat image = cv::imread("D:/images/beach.jpg");
	//设置直方图数据
	h.setRerenceImage(image);
	//定义double数组,保存相似度数据
	double similar[4];
	//group.jpg
	cv::Mat groupImage = cv::imread("D:/images/group.jpg");
	similar[0] = h.compare(groupImage);
	std::cout << "group:" << similar[0] << std::endl;
	//dog.jpg
	cv::Mat dogImage = cv::imread("D:/images/dog.jpg");
	similar[1] = h.compare(dogImage);
	std::cout << "dog:" << similar[1] << std::endl;
	//fundy.jpg
	cv::Mat fundyImage = cv::imread("D:/images/fundy.jpg");
	similar[2] = h.compare(fundyImage);
	std::cout << "fundy:" << similar[2] << std::endl;
	//waves.jpg
	cv::Mat wavesImage = cv::imread("D:/images/waves.jpg");
	similar[3] = h.compare(wavesImage);
	std::cout << "waves:" << similar[3] << std::endl;

	//找出相似度最大的数据
	double max = similar[1];
	int index = 0;
	for (int i = 0; i < 4; i++)
	{
		if (similar[i]>max)
		{
			max = similar[i];
			index = i + 1;
		}
	}
	//显示最相似的图片
	cv::namedWindow("最相似图片", CV_WINDOW_FREERATIO);
	switch (index)
	{
	case 1:
		cv::imshow("最相似图片", groupImage);
		break;
	case 2:
		cv::imshow("最相似图片", dogImage);
		break;
	case 3:
		cv::imshow("最相似图片", fundyImage);
		break;
	case 4:
		cv::imshow("最相似图片", wavesImage);
		break;
	default:
		break;
	}
	//显示原图
	cv::namedWindow("原图", CV_WINDOW_FREERATIO);
	cv::imshow("原图", image);
	cv::waitKey(0);
	return 0;
}

实验结果

opencv 查找相似度 Android opencv查找图片中的相似图片_相似图像检索


与参考图像最相似的图像为:waves.jpg(从数据可以看出dog.jpg与waves.jpg,远比起其他两张图片,同参考图像beach.jpg相似)

opencv 查找相似度 Android opencv查找图片中的相似图片_opencv_02