灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其横坐标是灰度级,纵坐标是该灰度出现的频率(像素的个数)。

在opencv中可以通过cvCreateHist()来生成直方图


CvHistogram* cvCreateHist(
    int dims,       
    int* sizes,   
    int type,    
    float** ranges=NULL, 
    int uniform=1  
    )
    dims   
    //直方图包含的维数
    sizes 
    //数组的长度等于dims,数组中每个整数表示分配给对应维数的的bin的个数
    type  
    //表示存储类型,CV_HIST_ARRAy表示用密集多维矩阵结构存储直方图,CV_HIST_SPARSE表示数据已稀疏矩阵方式存储
    ranges=NULL, 
    //浮点数对的构成的数组,每个浮点数对表示对应维数的bin的区间的上下界
    uniform=1  
    //非0表示均匀直方图,为NULL表示未知,即在后面可以设置。CvHistogram* cvCreateHist(


使用cvCalcHist()函数来计算直方图


void cvCalcHist(
IplImage** image,
CvHistogram* hist,
int accmulate=0,
const CvArr* mask=NULL
)
image  //是一个指向数组的IplImage*类型的指针,着允许利用多个图像通道
hist   //要计算的直方图
accmulate //非0时,表示直方图hist在读入图像之前没有被清零
mask //如果为非NULL,则只有与mask非零元素对应的像素点会被包含在计算直方图中。


1.单通道图像的直方图

#include "stdafx.h"
#include <highgui.h>
#include <math.h>
#include <cv.h>
int main()
{
IplImage* sourceImage=0;

//以单通道读入图像
if(!(sourceImage=cvLoadImage("YAYA.jpg",0)))
return -1;

int hdims=51;      //分配给对应维数的bin的个数
float rangesArray[]={0,255};
float* ranges[]={rangesArray};
float maxValue;

CvHistogram* histogram=0;
histogram=cvCreateHist(1,&hdims,CV_HIST_ARRAY,ranges,1);

IplImage* histImage;      //用来显示直方图
histImage=cvCreateImage(cvGetSize(sourceImage),8,3);
cvZero(histImage);

//计算直方图
cvCalcHist(&sourceImage,histogram,0,0);

//获取最大值
cvGetMinMaxHistValue(histogram,0,&maxValue,0,0);

cvConvertScale(histogram->bins,histogram->bins,maxValue?255./maxValue:0,0);

float binsWidth;
binsWidth=histImage->width/hdims;
CvScalar color=CV_RGB(255,255,255);
for(int i=0;i<hdims;i++)
{
double value=(cvGetReal1D(histogram->bins,i)*histImage->height/255);
cvRectangle(histImage,cvPoint(i*binsWidth,histImage->height),cvPoint((i+1)*binsWidth,(int)(histImage->height-value)),color,1,8,0);
}
//显示
cvNamedWindow("sourceImage",0);
cvNamedWindow("histImage",0);
cvShowImage("sourceImage",sourceImage);
cvShowImage("histImage",histImage);
//释放资源
cvDestroyAllWindows();
cvReleaseImage(&sourceImage);
cvReleaseImage(&histImage);
cvReleaseHist(&histogram);

cvWaitKey(-1);
return 0;
}

运行结果:

多通道图像的直方图

因为ccCalHist()只接受单通道图像,所以在调用cvCalcHist()之前,首先用cvSplit()将多通道图像分解为单通道图像。

#include "stdafx.h"
#include <highgui.h>
#include <math.h>
#include <cv.h>
int main()
{
    IplImage* sourceImage=0;
    if(!(sourceImage=cvLoadImage("YAYA.jpg",1)))
        return -1;

    IplImage* hsvImage=cvCreateImage(cvGetSize(sourceImage),8,3);
    cvCvtColor(sourceImage,hsvImage,CV_BGR2HSV);
    IplImage* h_plane=cvCreateImage(cvGetSize(sourceImage),8,1);
    IplImage* s_plane=cvCreateImage(cvGetSize(sourceImage),8,1);
    IplImage* v_plane=cvCreateImage(cvGetSize(sourceImage),8,1);
    cvSplit(hsvImage,h_plane,s_plane,v_plane,0);
    
    int h_bins=30,s_bins=32;
    CvHistogram* histogram;
    {
        int hist_size[]={h_bins,s_bins};
        float h_ranges[]={0,180};
        float s_ranges[]={0,255};
        float* ranges[]={h_ranges,s_ranges};
        histogram=cvCreateHist(
            2,
            hist_size,
            CV_HIST_ARRAY,
            ranges,
            1
            );
    }
    IplImage* planes[]={h_plane,s_plane};
    cvCalcHist(planes,histogram,0,0);
    cvNormalizeHist(histogram,1.0);
    int scale=10;
    IplImage* histImage=cvCreateImage(
        cvSize(h_bins*scale,s_bins*scale),8,3);
    cvZero(histImage);

    float maxValue;
    cvGetMinMaxHistValue(histogram,0,&maxValue,0,0);
    
    for(int h=0;h<h_bins;h++)
        for(int s=0;s<s_bins;s++)
        {
            float binValue=cvQueryHistValue_2D(histogram,h,s);
            int intensity=cvRound(binValue*255./maxValue);
            cvRectangle(
                histImage,
                cvPoint(h*scale,s*scale),
                cvPoint((h+1)*scale-1,(s+1)*scale-1),
                CV_RGB(intensity,intensity,intensity),
                CV_FILLED
                );
        }

        cvNamedWindow("hsvImage",1);
        cvNamedWindow("histImage",1);

        cvShowImage("hsvImage",hsvImage);
        cvShowImage("histImage",histImage);
        cvWaitKey(-1);
        cvDestroyAllWindows();
        cvReleaseImage(&sourceImage);
        cvReleaseImage(&histImage);
        cvReleaseHist(&histogram);
        return 0;
}

运行结果:

直方图的相似度

计算直方图相似度的函数如下:


double cvCompareHist(
const CvHistogram* hist1,
const CvHistogram* hist2,
int method;           //距离标准
)


method的取值有:

CV_COMP_CORREL     完全匹配为1,完全不匹配为-1,数值越大越匹配

CV_COMP_CHISQR      低分比高分匹配的程度高,完全匹配的值为0,完全不匹配为无限值

CV_COMP_INTERSECT   高分表示好匹配,低分表示坏匹配

CV_COMP_BHATTACHARYYA     低分表示好匹配,高分表示换匹配。完全匹配为0,完全不匹配为0.

#include "stdafx.h"
#include <highgui.h>
#include <math.h>
#include <cv.h>
using namespace std;
//对比两个直方图的相似度
int main()
{
    IplImage* templateImage=cvLoadImage("YAYA.jpg");
    if(!templateImage)
        return -1;
    IplImage* grayImage=cvCreateImage(cvGetSize(templateImage),8,1);
    cvCvtColor(templateImage,grayImage,CV_BGR2GRAY);
    //首先加载图片,然后将图片变为灰度图
    
    int hist_size=51;
    float range[]={0,255};
    float* ranges[]={range};

    CvHistogram* histogram;
    histogram=cvCreateHist(
        1,
        &hist_size,      //size  元素为对应bin的个数
        CV_HIST_ARRAY,
        ranges,
        1
        );
    cvCalcHist(&grayImage,histogram,0,0);

    IplImage* compareImage=cvLoadImage("YAYA2.jpg");
    if(!compareImage)
        return -1;
    IplImage* compareGrayImage=cvCreateImage(cvGetSize(compareImage),8,1);
    cvCvtColor(compareImage,compareGrayImage,CV_BGR2GRAY);
    //首先加载图片,然后将图片变为灰度图
    
    CvHistogram* compareHistogram;
    compareHistogram=cvCreateHist(
        1,
        &hist_size,
        CV_HIST_ARRAY,
        ranges,
        1
        );
    cvCalcHist(&compareGrayImage,compareHistogram,0,0);

    //对直方图进行归一化操作
    cvNormalizeHist(histogram,1);
    cvNormalizeHist(compareHistogram,1);
    //计算匹配系数
    double degree=cvCompareHist(histogram,compareHistogram,
        CV_COMP_CHISQR);
    cout<<degree<<endl;
    cvWaitKey(10000000);
    cvDestroyAllWindows();
    cvReleaseImage(&templateImage);
    cvReleaseImage(&grayImage);
    cvReleaseImage(&compareImage);
    cvReleaseImage(&compareGrayImage);
    cvReleaseHist(&compareHistogram);
    cvReleaseHist(&histogram);
    return 0;
}