目标:选出一个参考图像,找出一组图像中与参考图像最相似的图像。
相似图像检索:基于图像内容的相似度检索,可以利用两幅图像的直方图特征,评估两幅图像的直方图相似度,进而得到两幅图像的相似度。
第一步:直方图特征提取
函数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;
}
实验结果
与参考图像最相似的图像为:waves.jpg(从数据可以看出dog.jpg与waves.jpg,远比起其他两张图片,同参考图像beach.jpg相似)