首页 > 代码精文 > C/C++ > Opencv2相似图像检索
2016
10-23

Opencv2相似图像检索

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

第一步:直方图特征提取

函数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相似)
这里写图片描述

最后编辑:
作者:小企鹅
坚持+积累+学习
捐 赠如果您觉得这篇文章有用处,请支持作者!鼓励作者写出更好更多的文章!

留下一个回复