opencv基于颜色直方图的图像比较
程序员文章站
2024-03-25 18:47:22
...
opencv基于颜色直方图的图像比较
图像预处理
把图像分割,把要检测的图像分割为9个小图像。比如下图为待检索的图像,将其划分为9个小部分,分别对每部分比较最后计算平均值。
计算直方图并归一化
将图像划分为9个小部分后将图像转换为HSV空间
HSV空间的图像检索使用H(色调)和S(饱和度)分量计算直方图并比较。opencv中计算直方图调用函数calcHist,将直方图归一化要调用函数normalize。
比较相似度
在得到归一化的直方图后,要度量图像的相似度。常用的相似度度量方式有5种,分别是相关性比较(Correlation)、卡方比较(Chi-Square)、十字交叉比(Intersection)、巴氏距离(Bhattacharyya)和EMD距离。
程序选择了相关性比较和EMD距离来比较图像的相关性。
程序运行环境vs2015+opencv2.4.1
#include <opencv2/core/core.hpp>
#include "opencv2/opencv.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>
#include <string>
#include <stdlib.h>
#include <io.h>
#include < fstream>
#include <algorithm>
//运行环境vs2015+opencv2.4.1
using namespace std;
using namespace cv;
//读入文件夹下指定格式的所有文件,本程序是读取文件夹下所有jpg图片
void getFiles(string path, string file_format, vector<string>& files)
{
intptr_t hFile = 0;//intptr_t和uintptr_t是什么类型:typedef long int/ typedef unsigned long int
struct _finddata_t fileinfo;
string p, file_formatName;
if (0 != strcmp(file_format.c_str(), ""))
{
file_formatName = "\\*." + file_format;
}
else
{
file_formatName = "\\*";
}
if ((hFile = _findfirst(p.assign(path).append(file_formatName).c_str(), &fileinfo)) != -1)//assign方法可以理解为先将原字符串清空,然后赋予新的值作替换。
{
do
{
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
} while (_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
//用于数组降序排列
bool hightolow(float a, float b)
{
return a>b;
}
//图像分割
void rectImage(Mat* rectImg, Mat oImg) {
int m = oImg.cols;//宽
int n = oImg.rows;//高
rectImg[1] = oImg(Rect(0, 0, m / 3, n / 3));
rectImg[2] = oImg(Rect(m / 3, 0, m / 3, n / 3));
rectImg[3] = oImg(Rect(m / 3 * 2, 0, m / 3, n / 3));
rectImg[4] = oImg(Rect(0, n / 3, m / 3, n / 3));
rectImg[5] = oImg(Rect(m / 3, n / 3, m / 3, n / 3));
rectImg[6] = oImg(Rect(m / 3 * 2, n / 3, m / 3, n / 3));
rectImg[7] = oImg(Rect(0, n / 3 * 2, m / 3, n / 3));
rectImg[8] = oImg(Rect(m / 3, n / 3 * 2, m / 3, n / 3));
rectImg[9] = oImg(Rect(m / 3 * 2, n / 3 * 2, m / 3, n / 3));
}
//图像检索
void compareFacesByHist(string filePath, Mat orgImg)
{
vector<Mat> src;
vector<string> files;
string file_format = "jpg";
getFiles(filePath, file_format, files);
int number = files.size();//文件数量
//计算直方图所需参数
vector<Mat> signature1(10);
vector<Mat> signature2(10);
MatND hist1, hist2;
int scale = 10, histSize[] = { 8,8 }, ch[] = { 0,1 };
float h_ranges[] = { 0,180 };
float s_ranges[] = { 0,255 };
const float* ranges[] = { h_ranges,s_ranges };
Mat oimage[10];
Mat image[10];
int m = orgImg.cols;//宽
int n = orgImg.rows;//高
std::map<string, float> mymap;
std::map<string, float> mymapEMD;
//存放检索结果 大小与图像库图片数量相同
float compare[30];
float compareEMD[30];
//读取图像库
for (int i = 0; i < number; i++)
{
Mat img = imread(files[i]);
src.push_back(img);
}
//待检索图像分割并转换为HSV空间
rectImage(oimage, orgImg);
for (int i = 1; i < 10; i++) {
cvtColor(oimage[i], oimage[i], COLOR_RGB2HSV);
}
//从图像库依次读取图像检索
for (int i = 0; i < number; i++) {
double s = 0;
double similarityValue = 0;
float emd = 0;
float semd = 0;
mymap[files[i]] = 0;
/*
imge[1] = src[i](Rect(0, 0, a / 3, b / 3));
imge[2] = src[i](Rect(a / 3, 0, a / 3, b / 3));
imge[3] = src[i](Rect(a / 3 * 2, 0, a / 3, b / 3));
imge[4] = src[i](Rect(0, b / 3, a / 3, b / 3));
imge[5] = src[i](Rect(a / 3, b / 3, a / 3, b / 3));
imge[6] = src[i](Rect(a / 3 * 2, b / 3, a / 3, b / 3));
imge[7] = src[i](Rect(0, b / 3 * 2, a / 3, b / 3));
imge[8] = src[i](Rect(a / 3, b / 3 * 2, a / 3, b / 3));
imge[9] = src[i](Rect(a / 3 * 2, b / 3 * 2, a / 3, b / 3));*/
rectImage(image, src[i]);
for (int k = 1; k < 10; k++) {
//计算直方图并归一化
vector<Vec3f> sigv1, sigv2;
calcHist(&oimage[k], 1, ch, Mat(), hist1, 2, histSize, ranges, true, false);
normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, Mat());
cvtColor(image[k], image[k], COLOR_RGB2HSV);
calcHist(&image[k], 1, ch, Mat(), hist2, 2, histSize, ranges, true, false);
normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());
//直方图比较 改变最后一个参数可改变比较方式,当前参数为相关性比较
similarityValue = compareHist(hist1, hist2, CV_COMP_CORREL);
s = s + similarityValue;
//EMD距离比较
for (int h = 0; h < histSize[0]; h++)
for (int s = 0; s < histSize[1]; s++) {
float hval = hist1.at<float>(h, s);
float hva2 = hist2.at<float>(h, s);
if (hval != 0)
sigv1.push_back(Vec3f(hval, (float)h, (float)s));
sigv2.push_back(Vec3f(hva2, (float)h, (float)s));
}
signature1[k] = Mat(sigv1).clone().reshape(1);
signature2[k] = Mat(sigv2).clone().reshape(1);
emd = EMD(signature1[k], signature2[k], CV_DIST_L2);
semd = semd + emd;
}
semd = semd / 9;
s = s / 9;
compare[i] = s;
compareEMD[i] = semd;
mymap[files[i]] = s;
mymapEMD[files[i]] = semd;
//cout << "相似度:" << s << endl;
//cout << "emd:" << semd << endl;
}
sort(compare, compare + 30, hightolow);
sort(compareEMD, compareEMD + 30);
//输出检索出的图像 相关性比较
/*
for (int l = 0; l < 10; l++) {
string path;
for (std::map<string, float>::iterator it = mymap.begin(); it != mymap.end(); it++)
{
if (it->second == compare[l])
path = it->first;
}
Mat image = imread(path);
imshow("相关性" + std::to_string(compare[l]), image);
waitKey(200);
}*/
//输出检索出的图像 EMD距离
for (int l = 0; l < 10; l++) {
string path;
for (std::map<string, float>::iterator it = mymapEMD.begin(); it != mymapEMD.end(); it++)
{
if (it->second == compareEMD[l])
path = it->first;
}
Mat image = imread(path);
imshow("EMD" + std::to_string(compareEMD[l]), image);
waitKey(200);
}
waitKey(0);
}
int main()
{
vector<Mat> src;
//图片库路径
string filePath = "D:\\video-img\\testcompare\\images";
//待检索图像
Mat orgImg = imread("D:\\video-img\\testcompare\\images\\image15.jpg");
compareFacesByHist(filePath, orgImg);
waitKey(0);
return 0;
}