Opencv2相似图像检索

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

第一步:直方图特征提取

函数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相似)

这里写图片描述




本文固定链接:http://www.ithtw.com/thread-11025.htm
转载请注明:MrLee 11月前 于 IT十万个为什么 发表
最新回复 (0)
回复
登录发表 or 还没有账号?去注册