OpenCV入门(十九)--直方图用法

直方图就是对数据进行统计,将统计值组织到一个事先定义好的bin中,bin中的数值是从数据中计算出来的特征统计量,这些数据可以是诸如阶梯方向,色彩或其他特征。无论如何,直方图获得的是数据分布的统计图。通常直方图的维数要低于原始数据。

直方图的基本数据结构

CvHistogram

多维直方图

typedef struct CvHistogram
{
    int     type;
    CvArr*  bins;
    float   thresh[CV_MAX_DIM][2]; /* for uniform histograms */
    float** thresh2; /* for non-uniform histograms */
    CvMatND mat; /* embedded matrix header for array histograms */
}
CvHistogram;

bins : 用于存放直方图每个灰度级数目的数组指针,数组在cvCreateHist 的时候创建,其维数由cvCreateHist 确定(一般以一维比较常见)

要创建一个直方图,需要调用:

CreateHist

创建直方图

CvHistogram* cvCreateHist( int dims, int* sizes, int type,
                           float** ranges=NULL, int uniform=1 );
dims
直方图维数的数目
sizes
直方图维数尺寸的数组
type
直方图的表示格式: CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组 CvMatND; CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组 CvSparseMat.
ranges
图中方块范围的数组. 它的内容取决于参数 uniform 的值。这个范围的用处是确定何时计算直方图或决定反向映射(backprojected ),每个方块对应于输入图像的哪个/哪组值。
uniform
归一化标识。 如果不为0,则ranges[i](0<=i<cDims,译者注:cDims为直方图的维数,对于灰度图为1,彩色图为3)是包含两个元素的范围数组,包括直方图第i维的上界和下界。在第i维上的整个区域 [lower,upper]被分割成 dims[i] 个相等的块(译者注:dims[i]表示直方图第i维的块数),这些块用来确定输入象素的第 i 个值(译者注:对于彩色图像,i确定R, G,或者B)的对应的块;如果为0,则ranges[i]是包含dims[i]+1个元素的范围数组,包括lower0, upper0, lower1, upper1 == lower2, ..., upperdims[i]-1, 其中lowerj 和upperj分别是直方图第i维上第 j 个方块的上下界(针对输入象素的第 i 个值)。任何情况下,输入值如果超出了一个直方块所指定的范围外,都不会被 cvCalcHist 计数,而且会被函数 cvCalcBackProject 置零。

函数 cvCreateHist 创建一个指定尺寸的直方图,并且返回创建的直方图的指针。 如果数组的 ranges 是 0, 则直方块的范围必须由函数 cvSetHistBinRanges 稍后指定。虽然 cvCalcHist 和 cvCalcBackProject 可以处理 8-比特图像而无需设置任何直方块的范围,但它们都被假设等分 0..255 之间的空间。


设置ranges,当cvCreateHist 中的值为0时,必须由下面的函数设置直方块的范围

SetHistBinRanges

设置直方块的区间

void cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform=1 );

hist

直方图.

ranges

直方块范围数组的数组,见 cvCreateHist.

uniform

归一化标识,见 cvCreateHist.

函数 cvSetHistBinRanges 是一个独立的函数,完成直方块的区间设置。更多详细的关于参数 ranges 和 uniform 的描述,请参考函数 cvCalcHist , 该函数也可以初始化区间。直方块的区间的设置必须在计算直方图之前,或 在计算直方图的反射图之前。


直方图的清除:

ClearHist

清除直方图

void cvClearHist( CvHistogram* hist );
hist
直方图.

函数 cvClearHist 当直方图是稠密数组时将所有直方块设置为 0,当直方图是稀疏数组时,除去所有的直方块。


ReleaseHist

释放直方图结构

void cvReleaseHist( CvHistogram** hist );
hist
被释放的直方图结构的双指针.

函数 cvReleaseHist 释放直方图 (头和数据). 指向直方图的指针被函数所清空。如果 *hist 指针已经为 NULL, 则函数不做任何事情。


根据已经给出的数据创建直方图:

MakeHistHeaderForArray

从数组中创建直方图

CvHistogram*  cvMakeHistHeaderForArray( int dims, int* sizes, CvHistogram* hist,
                                        float* data, float** ranges=NULL, int uniform=1 );
dims
直方图维数.
sizes
直方图维数尺寸的数组
hist
为函数所初始化的直方图头
data
用来存储直方块的数组
ranges
直方块范围,见 cvCreateHist.
uniform
归一化标识,见 cvCreateHist.

函数 cvMakeHistHeaderForArray 初始化直方图,其中头和直方块为用户所分配。以后不需要调用 cvReleaseHist 只有稠密直方图可以采用这种方法,函数返回 hist.


访问直方图:

QueryHistValue_1D

查询直方块的值

#define cvQueryHistValue_1D( hist, idx0 ) \
    cvGetReal1D( (hist)->bins, (idx0) )
#define cvQueryHistValue_2D( hist, idx0, idx1 ) \
    cvGetReal2D( (hist)->bins, (idx0), (idx1) )
#define cvQueryHistValue_3D( hist, idx0, idx1, idx2 ) \
    cvGetReal3D( (hist)->bins, (idx0), (idx1), (idx2) )
#define cvQueryHistValue_nD( hist, idx ) \
    cvGetRealND( (hist)->bins, (idx) )
hist
直方图
idx0, idx1, idx2, idx3
直方块的下标索引
idx
下标数组

宏 cvQueryHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方图的指定直方块的值。对稀疏直方图,如果方块在直方图中不存在,函数返回 0, 而且不创建新的直方块。


GetHistValue_1D

返回直方块的指针

#define cvGetHistValue_1D( hist, idx0 ) \
    ((float*)(cvPtr1D( (hist)->bins, (idx0), 0 ))
#define cvGetHistValue_2D( hist, idx0, idx1 ) \
    ((float*)(cvPtr2D( (hist)->bins, (idx0), (idx1), 0 ))
#define cvGetHistValue_3D( hist, idx0, idx1, idx2 ) \
    ((float*)(cvPtr3D( (hist)->bins, (idx0), (idx1), (idx2), 0 ))
#define cvGetHistValue_nD( hist, idx ) \
    ((float*)(cvPtrND( (hist)->bins, (idx), 0 ))
hist
直方图.
idx0, idx1, idx2, idx3
直方块的下标索引.
idx
下标数组

宏 cvGetHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方图的指定直方块的指针。对稀疏直方图,函数创建一个新的直方块,且设置其为 0,除非它已经存在。


直方图的基本操作:

NormalizeHist

归一化直方图

void cvNormalizeHist( CvHistogram* hist, double factor );
hist
直方图的指针.
factor
归一化因子

函数 cvNormalizeHist 通过缩放来归一化直方块,使得所有块的和等于 factor.


ThreshHist

对直方图取阈值

void cvThreshHist( CvHistogram* hist, double threshold );
hist
直方图的指针.
threshold
阈值大小

函数 cvThreshHist 清除那些小于指定阈值得直方块


CopyHist

拷贝直方图

void cvCopyHist( const CvHistogram* src, CvHistogram** dst );
src
输入的直方图
dst
输出的直方图指针

函数 cvCopyHist 对直方图作拷贝。如果第二个直方图指针 *dst 是 NULL, 则创建一个与 src 同样大小的直方图。否则,两个直方图必须大小和类型一致。然后函数将输入的直方块的值复制到输出的直方图中,并且设置取值范围与 src 的一致。

CalcHist

计算图像image(s) 的直方图

void cvCalcHist( IplImage** image, CvHistogram* hist,
                 int accumulate=0, const CvArr* mask=NULL );
image
输入图像s (虽然也可以使用 CvMat** ).
hist
直方图指针
accumulate
累计标识。如果设置,则直方图在开始时不被清零。这个特征保证可以为多个图像计算一个单独的直方图,或者在线更新直方图。
mask
操作 mask, 确定输入图像的哪个象素被计数


GetMinMaxHistValue

发现最大和最小直方块

void cvGetMinMaxHistValue( const CvHistogram* hist,
                           float* min_value, float* max_value,
                           int* min_idx=NULL, int* max_idx=NULL );
hist
直方图
min_value
直方图最小值的指针
max_value
直方图最大值的指针
min_idx
数组中最小坐标的指针
max_idx
数组中最大坐标的指针

函数 cvGetMinMaxHistValue 发现最大和最小直方块以及它们的位置。任何输出变量都是可选的。在具有同样值几个极值中,返回具有最小下标索引(以字母排列顺序定)的那一个。


代码:输入一个图像,计算出饱和度直方图,然后利用网格的形式显示
/*
*直方图的用法示例
*/

#include "highgui.h"
#include "cv.h"

void doHist1(IplImage* img)
{
	IplImage* hsv = cvCreateImage(cvGetSize(img), 8, 3);
	IplImage* h_plane = cvCreateImage(cvGetSize(img), 8, 1);
	IplImage* s_plane = cvCreateImage(cvGetSize(img), 8, 1);
	IplImage* v_plane = cvCreateImage(cvGetSize(img), 8, 1);

	IplImage* planes[] = {h_plane, s_plane};

	//设置直方图每个灰度级的数目
	int h_bins = 30;
	int s_bins = 32;
	
	int hist_size[] = {h_bins, s_bins};
	float h_ranges[] = {0, 180};
	float s_ranges[] = {0, 255};
	float* ranges[] = {h_ranges, s_ranges};
	int scale = 10;
	IplImage* hist_img = cvCreateImage(cvSize(h_bins* scale , s_bins*scale), 8, 3);
	CvHistogram* hist;
	float max_value = 0;
	int h, s;

	cvCvtColor(img, hsv, CV_BGR2HSV);
	cvCvtPixToPlane(hsv, h_plane, s_plane, v_plane, 0); //cvSplit的一个宏
	
	
	// 计算图像的直方图
	hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
	cvCalcHist(planes, hist, 0, 0);
	//cvNormalizeHist(hist, 1.0);
	cvGetMinMaxHistValue(hist, 0, &max_value, 0, 0);
	cvZero(hist_img);

	//cvNormalizeHist(hist, 1.0);
	for(int h = 0; h < h_bins; h++)
	{
		for(int s = 0; s < s_bins; s++)
		{
			float bin_val = cvQueryHistValue_2D(hist, h,s);
			int intensity = cvRound(bin_val * 255/ max_value);
			cvRectangle(
				hist_img,
				cvPoint(h*scale, s*scale),
				cvPoint((h+1)*scale - 1, (s+1)*scale -1),
				CV_RGB(intensity, intensity,intensity),
				CV_FILLED
				);
		}
	}
    cvNamedWindow( "H-S Histogram", 1 );
    cvShowImage( "H-S Histogram", hist_img );
	cvWaitKey(0);
}

结果:










  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值