我的OpenCV学习笔记(14):用直方图对比完成基于内容的图像检索

我们知道,直方图可以在一定程度上反应图像的一些统计信息。所以,可以考虑用直方图对比的方法,进行基于内容的图像检索。

通常我们搜索图片,都是根据图片的标签搜索的。基于内容的搜索,就是假设我们不知道标签,而是直接输入一幅图像,然后从得出一些跟这幅图像的直方图比较相似的图像。

那么我们不禁要问,如何度量两幅直方图的相似程度呢?

OpenCV的compareHist函数提供了一个参数供你选择。最简单的就是CV_COMP_INTERSECT。这个方法原理其实很简单,就是对于两幅的同一个bin,选择他们的最小值,然后把所有的bin都加起来。举个例子,如果两幅图像没有任何相同的颜色,那么这个比较的计算结果就为0;如果是两幅完全相同的图像,那么计算结果就应该是整幅图像的像素数。其他的度量方法可以参考OpenCV的帮助手册,这里就不一一细说了。

下面看看代码吧。因为需要计算彩色图像的直方图,所以先建立一个计算彩色图像直方图的类:

#if!defined COLORHISTOGRAM
#define COLORHISTOGRAM

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

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;
	}

	//计算彩色图像直方图
	Mat getHistogram(const Mat& image)
	{
		Mat hist;

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

		//计算
		calcHist(&image,1,channels,Mat(),hist,3,histSize,ranges);
		return hist;
	}

	//计算颜色的直方图
	Mat getHueHistogram(const Mat &image)
	{
		Mat hist;
		Mat hue;
		//转换到HSV空间
		cvtColor(image,hue,CV_BGR2HSV);

		//设置1维直方图使用的参数
		hranges[0] = 0.0;
		hranges[1] = 180.0;
		channels[0] = 0;
		//计算直方图
		calcHist(&hue,1,channels,Mat(),hist,1,histSize,ranges);
		return hist;

	}

	//减少颜色
	Mat colorReduce(const Mat &image,int div = 64)
	{
		int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));
		uchar mask = 0xFF<<n;
		Mat_<Vec3b>::const_iterator it = image.begin<Vec3b>();
		Mat_<Vec3b>::const_iterator itend = image.end<Vec3b>();
		//设置输出图像
		Mat result(image.rows,image.cols,image.type());
		Mat_<Vec3b>::iterator itr = result.begin<Vec3b>();
		for(;it != itend;++it,++itr)
		{
			(*itr)[0] = ((*it)[0]&mask) + div/2;
			(*itr)[1] = ((*it)[1]&mask) + div/2;
			(*itr)[2] = ((*it)[2]&mask) + div/2;
		}
		return result;
	}

};


#endif


然后再建立一个比较直方图的类:

#if!defined IMAGECOMPARATOR
#define IMAGECOMPARATOR

#include "colorhistogram.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

class ImageComparator
{
private:
	Mat reference;
	Mat input;
	Mat refH;
	Mat inputH;
	ColorHistogram hist;
	int div;
public:
	ImageComparator():div(32){}

	void setColorReducation(int factor)
	{
		div = factor;
	}

	int getColorReduction()
	{
		return div;
	}

	void setRefrenceImage(const Mat &image)
	{
		reference = hist.colorReduce(image,div);
		refH = hist.getHistogram(reference);
	}

	double compare(const Mat &image)
	{
		input = hist.colorReduce(image,div);
		inputH = hist.getHistogram(input);
		return compareHist(refH,inputH,CV_COMP_INTERSECT);
	}
};


#endif


注意到在计算直方图前,我对图像的颜色进行了减少,这样做的主要目的是为了减少运算量。

有了这两个类,我们的主程序就变得简单多了:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include "imageComparator.h"

#include <iostream>

using namespace std;

int main()
{
	Mat image = imread("D:/picture/images/waves.jpg");
	if(!image.data)
		return -1;
	imshow("待检测图像",image);
	cout<<"图像像素数为:"<<image.cols*image.rows<<endl;

	ImageComparator c;
	c.setRefrenceImage(image);

	//跟自己比
	Mat input = imread("D:/picture/images/waves.jpg");
	imshow("自己",input);
	cout<<"waves VS waves:"<<c.compare(input)<<endl;

	input = imread("D:/picture/images/dog.jpg");
	imshow("dog",input);
	cout<<"waves VS dog:"<<c.compare(input)<<endl;

	input = imread("D:/picture/images/marais.jpg");
	imshow("沼泽",input);
	cout<<"waves VS marsh:"<<c.compare(input)<<endl;

	input= cv::imread("D:/picture/images/bear.jpg");
	imshow("熊",input);
	cout<<"waves VS bear:"<<c.compare(input)<<endl;


	waitKey(0);
	return 0;
}


正如前面所说的,如果自己跟自己比较,结果就是整幅图像像素数。

最后,做一点小小的说明,这里演示的直方图比较法其实不是特别靠谱。举一个简单的例子,对于一幅图像,如果把它进行翻转,或者分割以后在重新随机组合起来(尽管结果可能没有什么意义),尽管图像发生了显著地变化,但是他的直方图是不会变的。所以又有人想出了对图像分块,然后再做直方图之类的方法。我也不是这方面的专家,如果大家真的想弄一个靠谱的做法,最好是查查论文,看看牛人们都是怎么搞的。

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
大规模图像检索的代码,matlab与c++混合编程。总结了目前图像检索领域目前主要存在的方法。通过阅读该代码,可以对于经典的“词袋”模型(bow模型)有个具体的了解,但是该代码没有提供前序的特征提取,是直接从对提取好的特征向量聚类开始的,包括了k-means,分层k-means(HKM)聚类,倒排文件的建立和索引等,该代码还提供了局部敏感哈希(LSH)方法。最后,这份代码是下面这篇论文的作者提供的, Indexing in Large Scale Image Collections: Scaling Properties and Benchmark-This C++/Matlab package implements several algorithms used for large scale image search. The algorithms are implemented in C++, with an eye on large scale databases. It can handle millions of images and hundreds of millions of local features. It has MEX interfaces for Matlab, but can also be used (with possible future modifications) from Python and directly from C++. It can also be used for approximate nearest neighbor search, especially using the Kd-Trees or LSH implementations. The algorithms can be divided into two broad categories, depending on the approach taken for image search: 1. Bag of Words: ---------------- The images are represented by histograms of visual words. It includes algorithms for computing dictionaries: * K-Means. * Approximate K-Means (AKM). * Hierarchical K-Means (HKM). It also includes algorithms for fast search: * Inverted File Index. * Inverted File Index with Extra Information (for example for implementing Hamming Embedding).
要使用compareHist函数进行图像直方图比较,需要先将要比较的两幅图像的直方图计算出来。具体步骤如下: 1. 导入必要的库: ```python import cv2 import numpy as np from matplotlib import pyplot as plt ``` 2. 加载要比较的两幅图像: ```python img1 = cv2.imread('image1.png') img2 = cv2.imread('image2.png') ``` 3. 将图像转为HSV空间,并计算直方图: ```python hsv1 = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV) hsv2 = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV) hist1 = cv2.calcHist([hsv1], [0, 1], None, [180, 256], [0, 180, 0, 256]) hist2 = cv2.calcHist([hsv2], [0, 1], None, [180, 256], [0, 180, 0, 256]) ``` 其中,第一个参数是要计算直方图的图像,第二个参数是通道,[0, 1] 表示计算H和S通道的直方图,第三个参数是掩膜,这里不使用,第四个参数是直方图的大小,第五个参数是每个通道的取值范围。 4. 使用compareHist函数进行直方图比较: ```python # 使用相关性比较方法 corr = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL) print('Correlation:', corr) # 使用卡方比较方法 chi = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR) print('Chi-Square:', chi) # 使用交叉熵比较方法 cross = cv2.compareHist(hist1, hist2, cv2.HISTCMP_INTERSECT) print('Intersection:', cross) # 使用巴氏距离比较方法 bhat = cv2.compareHist(hist1, hist2, cv2.HISTCMP_BHATTACHARYYA) print('Bhattacharyya:', bhat) ``` 其中,第一个参数是要比较的直方图1,第二个参数是要比较的直方图2,第三个参数是比较方法,可以选择相关性、卡方、交叉熵或巴氏距离。 5. 可以将比较结果可视化: ```python plt.subplot(121), plt.imshow(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)) plt.title('Image 1'), plt.xticks([]), plt.yticks([]) plt.subplot(122), plt.imshow(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)) plt.title('Image 2'), plt.xticks([]), plt.yticks([]) plt.show() ``` 这样就可以使用Python Opencv中的compareHist函数进行图像直方图比较了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值