1、一维直方图:单通道,bin是一条直线
二维直方图:双通道,bin是一个矩形
2、直方图的结构体:CvHistogram
typedef struct CvHistogram
{
int type;
CvArr* bins; 存放直方图在每一维上直方柱的具体数据,由于存在多维直方图。如果是一维直方图,那么bins就是一个一维 的矩阵;如果是二维直方图,那么bins就是一个二维的矩阵,等等。
float thresh[CV_MAX_DIM][2]; /* 直方柱的划分 是统一划分的,即均等划分的 */
float** thresh2; /*不均等划分,可以自动设定每一个直方柱的取值范围。之所以是二级指针,每一个柱的取值范围用一级指针表示,又存在多个直方柱,所以需要二级指针才能表示。每一个不在指定范围的值,会被忽略掉。*/
CvMatND mat; /* 存放直方图的数据 */
}
3、CvHistogram* cvCreateHist( int dims, int* sizes, int type,float** ranges=NULL, int uniform=1 ); 创建一个直方图的函数
dims:表示直方图的维度
sizes:每一维上直方柱(bin)的数据
type:直方图存储数据的方式:CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组CvMatND; CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组CvSparseMat.
ranges:直方图在每一维度上的范围。
uniform:存每一维的坐标的取值范围。该值为0时,表示bin的范围是程序员自由设定的。当该值为非零时,表示bin的划分,是均等划分。
注:在创建完一个直方图后,必须调用cvClearHist(hist)函数,去掉一些不必要的随机值
4、给某个通道分配相应的空间:IplImage* b_img=cvCreateImage(cvGetSize(img),8,1);
5、cvSplit(img,b_img,g_img,r_img,NULL); 把图img像分解成四个通道,且这三个通道的顺序必须是B、G、R
6、计算每一个通道的直方图,即每个通道上的每个直方柱的大小(高度):cvCalcHist(&b_img,hist,0,0); //计算b_img这个通道的直方图的大小,结果存在hist里面
7、找出htist这个直方图里面哪个直方柱的值最大,并将该最大值存在histmax里面,为了做归一化:
float histmax=0; cvGetMinMaxHistValue(hist,0,&histmax,0,0);
8、获取直方图hist里边第i个bin的值:float pt=cvQueryHistValue_1D(hist,i);
// 图像的灰度直方图.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
IplImage* DrawHistogram(CvHistogram* hist,int scaleX=1,int scaleY=1)
{
float histmax=0;
cvGetMinMaxHistValue(hist,0,&histmax,0,0);
IplImage* histImg=cvCreateImage(cvSize(256*scaleX,64*scaleY),8,1);
cvZero(histImg);
for(int i=0;i<255;i++)
{
float pt=cvQueryHistValue_1D(hist,i); //获取直方图hist里边第i个bin的值
float pt_next=cvQueryHistValue_1D(hist,i+1); //获取直方图hist里边第i+1个bin的值
CvPoint pt1=cvPoint(i*scaleX,64*scaleY); //第i个点的坐标
CvPoint pt2=cvPoint((i+1)*scaleX,64*scaleY); //第i+1个点的坐标
CvPoint pt3=cvPoint((i+1)*scaleX,(64-pt_next/histmax*64)*scaleY); //归一化
CvPoint pt4=cvPoint(i*scaleX,(64-pt/histmax*64)*scaleY);
CvPoint pts[5];
int numPts=5;
pts[0]=pt1;
pts[1]=pt2;
pts[2]=pt3;
pts[3]=pt4;
pts[4]=pt1;
//不能直接这样子赋值:CvPoint pts[5]={pt1,pt2,pt3,pt4,pt5};
cvFillConvexPoly(histImg,pts,numPts,cvScalar(255)); //填充由这四个点构成的矩形
}
return histImg;
}
int main(int argc, char* argv[])
{
IplImage* img=cvLoadImage("E:\\大四上\\openCV\\图片\\机器猫.jpg");
IplImage* b_img=cvCreateImage(cvGetSize(img),8,1); //单通道图像
IplImage* g_img=cvCreateImage(cvGetSize(img),8,1);
IplImage* r_img=cvCreateImage(cvGetSize(img),8,1);
int dims=1; //直方图的维度
int size=256;
float range[]={0,255};
float *ranges[]={range}; //取值范围
CvHistogram* hist=cvCreateHist(dims,&size,CV_HIST_ARRAY,ranges,1); //创建一个直方图
cvClearHist(hist); //清除直方图,去掉一些不必要的随机值
cvSplit(img,b_img,g_img,r_img,NULL); //把图像分解成四个通道
cvCalcHist(&b_img,hist,0,0); //计算b_img这个通道的直方图的大小,结果存在hist里面
b_img=DrawHistogram(hist);
cvNamedWindow("b_img");
cvShowImage("b_img",b_img);
cvClearHist(hist);
cvCalcHist(&g_img,hist,0,0); //计算b_img这个通道的直方图的大小,结果存在hist里面
g_img=DrawHistogram(hist);
cvNamedWindow("g_img");
cvShowImage("g_img",g_img);
cvClearHist(hist);
cvCalcHist(&r_img,hist,0,0); //计算b_img这个通道的直方图的大小,结果存在hist里面
r_img=DrawHistogram(hist);
cvNamedWindow("r_img");
cvShowImage("r_img",r_img);
cvClearHist(hist);
cvWaitKey(0);
//(1) 释放源图像
cvReleaseImage(&img);
//(2) 释放三个通道的图像
cvReleaseImage(&r_img);
cvReleaseImage(&g_img);
cvReleaseImage(&b_img);
//(4)释放直方图空间
cvReleaseHist(&hist);
return 0;
}