目录
前言
学习!分享!感谢!
直方图概述
直方图是一个统计学概念,图像的直方图用来表现图像中亮度分布的直方图,给出图像中某个亮度或者某个亮度下像素个数。直方图将统计值组织到一系列事先定义好的bin
(直条或组距)中,其数值是从数据中计算出的特征统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。且无论如何,直方图获得的是数据分布的统计图。
在统计学中,直方图(Histogram
)是一种对数据分布情况的图形表示,是一种二维统计图表,它的两个坐标分别是统计样本和该样本对应的某个属性的度量。图像直方图是用一表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素数。可以借助观察该直方图了解需要如何调整亮度分布的直方图。这种直方图中,横坐标的左侧为纯黑、较暗的区域,而右侧为较亮、纯白的区域。因此,一张较暗图片的图像直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。计算机视觉邻域常借助图像直方图来实现图像的二值化。
灰度直方图是一幅图像中个像素灰度值出现次数或频数的统计结果,它只反映该图像中灰度值出现的频率,而未反映某一灰度值像素所在的位置。也就是说,它只包含了该图像中某个灰度值的像素出现的概率,而丢失了其所在的位置的信息。
任一幅图像,都能唯一地算出一幅与它对应的直方图。但不同的图像,可能有相同的直方图。即图像与直方图之间是多对一的映射关系。
由于直方图是对具有相同灰度值的像素统计计数得到的,因此,一幅图像各子区(把一幅图像分割成子区)的直方图之和等于该图全图的直方图。
直方图意义:
1. 直方图是图像中像素强度分布的图形表达方式。
2. 直方图统计了每一个强度值所具有的像素个数。
直方图是对数据的统计集合,并将统计结果分布于一系列的预定义的bins
中。这里的数据不仅仅指的是灰度值,且统计数据可能是任何能有效描述图像的特征。
直方图通过标记帧和帧之间显著的边缘和颜色的统计变化,来检测视频中场景的变化。在每个兴趣点设置一个有相近特征的直方图所构成的标签,用以确定图像中的兴趣点。边缘、色彩、角度等直方图构成了可以被传递给目标识别分类器的一个通用特征类型。
直方图术语:
dims
:需要统计的特征的数目。例如:dims=1
,表示我们仅统计灰度值。
bins
:每个特征空间子区段的数目。
range
:每个特征空间的取值范围。
参考《OpenCV3编程入门毛星云编著电子工业出版》
直方图对比
对于直方图来说,一个不可或缺的工具便是用某些具体的标准来比较两个直方图的相似度。要对两个直方图进行比较,首先必须选择一个衡量直方图相似度的对比标准 d(H1,H2) 。
OpenCV1.0直方图函数
cvCreateHist
功能:创建一个指定尺寸的直方图,并且返回创建的直方图的指针。
CvHistogram* cvCreateHist( int dims, int* sizes, int type, float**
ranges=NULL, int uniform=1 );
参数:
dims
:直方图维数的数目
sizes
:直方图维数尺寸的组数,size
数组的长度表示分配给对应维数的bin
个数。如dims=3
,则size
中用[s1, s2, s3]分别指定每维bin
的个数。
type
:直方图的表示格式:CV_HIST_ARRAY
意味着直方图数据表示为多维密集数组CvMatND
;CV_HIST_TREE
意味着直方图表示为多维稀疏数组CvSparseMat
。
ranges
:图中方块范围的数组。它的内容取决于参数uniform
的值。这个范围的用处是确定何时计算直方图或决定反向映射,每个方块对应于输入图像的哪个/哪组值。
uniform
:归一化标识。如果不为0(不均匀),则ranges[i]
(0=i<cDims
,cDims
是直方图的维数,对于灰度图为1,彩色图为3)是包含两个元素范围数组,包括直方图第i
维的上界和下界。在第i
维上的整个区域[lower, upper]
被分割成dims[i]
个相等的块;如果为0(ranges均匀),则ranges[i]
是包含dims[i]+1
个元素的范围数组,包括lower0, upper0, lower1, upper1...
,其中lowerj
和upperj
分别是直方图第i
维上第j
个方块的上下界。任何情况下,输入值如果超出直方块所指定的范围外,都不会被cvCalHist
计数,而且会被函数cvBackProject
置零。
灰度直方图是灰度级的函数,描述图像中该灰度级的像素个数:其横坐标是灰度级,纵坐标表示图像中该灰度级出现的个数。高维直方图可以理解为图像在每个维度上灰度级分布的直方图。常见的二维直方图,如红蓝直方图的两个分量分别表示红光图像的灰度值和蓝光图像的灰度值。其图像坐标(Dr, Db)处对应在红光图像中具有灰度级Dr
,同时在蓝光图像中具有灰度级Db
的像素个数。
例如:
#define DEPTH 3
#define LBPBINS 36
#define LBPSIZE 36
#define MAXHUE 180
int histSize[] = {32, 16, LBPBINS};
float* hranges[] = {hranges_arr, sranges_arr, vranges_arr};
float hranges_arr[] = {0,MAXHUE};
float sranges_arr[] = {0,255};
float vranges_arr[] = {0,LBPSIZE-1};
histTarget=cvCreateHist( DEPTH, histSize, CV_HIST_ARRAY, hranges, 1 );
/*
参数1:DEPTH等于3,表示直方图是3维的
参数2:histSize表示直方图维数尺寸的组数,size数组的长度表示分配给对应维数的bin个数,也就是第一维有32个bins,第二维有16个bins,第三维有36个bins.
参数3:CV_HIST_ARRAY表示直方图数据为多维密集数组CvMatND
参数4:图中方块范围的数组,第一维是0~180,,第二维是0~255,第三维是0~35.
参数5:归一化标识。如果不为0,则range[i]是包含两个元素范围的数组,包括直方图第i维的上界和下界。在第i维上的整个区域[lower, upper]被分割成dims[i]个相等的块。
可以看做是一个立方体应该,水平x轴是被划分为32等分(范围0~180),水平y轴是被划分为16等分(范围0~255),垂直z轴被划分为36等分(范围0~35),也就是对应的每一个hist的值是一个小立方体,这个立方体比如标记为(100, 100, 100),然后去源HSV图像中查找有多少点是这个值,然后填充这个点的值,最后如果数值归一化到255,就表示为一张灰度图,只不过这里如果从三维角度看,是把一个立方体设置为一个灰度颜色
*/
cvCalcHist
功能:计算一张或多张单通道图像的直方图。
void cvCalcHist(
IplImage** image,
CvHistogram* hist,
int accumulate = 0,
const CvArr* mask = NULL
);
/*
image:指向数组的IplImage*类型指针。这允许利用多个图像通道。对于多通道图像(如HSV或RGB),在调用函数cvCalcHist()之前,先要用函数cvSplit()将图像分为单通道。总之传递给cvCalcHist()的图像都被假设为单通道图像。
hist:直方图指针
accumulate:表示如果非0,表示直方图hist在读入图像之前没有被清零。注意,变量accumlate运行cvCalcHist()在一个数据采集循环中被多次调用。
mask:一个可选的布尔变量,如果被设为非NULL,则只有与mask非0元素对应的像素点会被包含在计算直方图中。
*/
举例:
cvThreshold(imgrm, imgrm, 128, 255, CV_THRESH_BINARY_INV);
cvCalcHist( imgip, histB, 0, imgrm );
参数1:imgip是三通道HSV图,已经被cvSplit为三个单通道的数组
参数2:histB是直方图指针,此处是三维直方图指针
参数3:0表示hist在读入图像之前被清零。
参数4:imgrm 是一个可选的布尔变量,如果被设置为非NULL,则只有与imgrm非0元素对应的像素点会被包含在计算直方图中
imgrm进行了阈值化,目前博主认为就是通过cvCalHist计算出了分离的三通道数组的三维直方图,同时对直方图进行阈值化的意思
cvNormalizeHist
void cvNormalizeHist(CvHistogram* hist, double factor);
/*
hist:直方图指针
factor:归一化因子
通过缩放来归一化直方图,使得所有块的和等于factor
*/
cvThreshHist
cvThreshHist(CvHistogram* hist, double factor);
/*
hist:传入的直方图
factor:开关阈值。进入直方图阈值化处理之后,小于给定阈值的各个bin的值都被设为0.类似于阈值函数cvThreshold(),参数threshold_type设置为CV_THRESH_TOZERO(小于阈值设置为0,大于阈值保持不变)。实际使用是常常用于将包含极少数据点的bins去除掉。这些bins通常是噪声,因此设置为0
*/
cvThreshold
void cvThreshold( const CvArr* src, CvArr* dst, double threshold,
double max_value, int threshold_type );
/*
src:输入数组,填单通道,8或32位浮点类型
dst:输出数组,和src有一样的尺寸和类型
threshold:阈值的具体值
max_value:使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值
threshold_type:阈值类型。用于确定对超过阈值和低于阈值时的阈值化图像确定。比如THRESH_TRUNC,当原始图的阈值大于阈值设定值时,设定值为threshold,小于阈值时为原来的值。具体参考《OpenCV3编程入门_毛星云编著》P238
*/
举例:
IplImage *imgrm = cvCreateImage( CvSize(640, 480), 8, 1 );
cvThreshold(imgrm, imgrm, 128, 255, CV_THRESH_BINARY_INV);
参数1:src 输入数组,单通道
参数2:dst 输出数组,和输入数组有一样的尺寸和类型
参数3:threshold 阈值的具体指
参数4:max_value 使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值
参数5:threshold_type.阈值类型表示THRESH_BINARY_INV 表示源图像像素值如果大于阈值threshold,则表示为0;反之为原值
cvCopyHist
void cvCopyHist(const CvHistogram* src, CvHistogram** dst);
/*
如果目标直方图*dst和源直方图有相同的大小,那么src中所有的数据和bin的范围都被复制到*dst.另一种使用cvCopyHist()的方式是设置*dst为NULL.这种情况下,生成一个与src一样大的新直方图,所有数据和bin的范围都被复制到该直方图中。注意:如果第二个参数不是NULL,第二个参数dst是一个指向直方图指针的指针,而如果*dst为NULL,则当该函数返回时,*dst被分配给一个指向新分配的直方图的指针。
*/
cvGetMinMaxHistValue
void cvGetMinMaxHistValue(
const CvHistogram* hist,
float* min_value,
float* max_value,
int* min_idx = NULL,
int* max_idx = NULL
);
/*
给定直方图hist,函数cvGetMinMaxHistValue()将计算其最小值和最大值。当该函数返回时,*min_value和*max_value将分别被设置为这两个极值。如果不需要其中的一个(或两个)值,可以设置相应变量为NULL.min_idx和max_idx如果为非NULL,则函数返回最小和最大值的索引值。对于多维直方图,参数min_idx和max_idx(如果非NULL)被设为指向一个整数数组的指针,数组长度等于直方图维数。如果一个直方图中有许多个bin的值都为最小值或最大值,则返回具有最小索引的bin。
*/
总结:在收集直方图数据后,通常利用cvGetMinMaxHistValue
来寻求最小值,同时利用函数cvThreshHist
在最小值附近进行阈值化操作,最终通过函数cvNormalizeHist
来归一化直方图。
cvRound
功能:返回跟参数最接近的整数值
OpenCV2.0直方图函数
calHist
功能:计算一个或者多个阵列的直方图。
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
)
/*
参数1:const Mat*类型的images,输入的数组(或数组集),它们需为相同的深度(CV_8U或CV_32F)和相同的尺寸。
参数2:int类型的nimages,输入数组的个数,也就是第一个参数中存放了多少张图像,有几个源数组
参数3:const int*类型的channels,需要统计的通道索引。第一个数组通道从0到image[0].channels-1,第二个数组通道从images[0].channes()计算到images[0].channels()+images[1].channels()-1
参数4:InputArray类型的mask,可选的操作掩码。如果此掩码不为空,那么它必须为8位,并且与images[i]有同样大小的尺寸。这里的非零掩码元素用于标记出统计直方图的数组元素数据。
参数5:OutputArray类型的hist,输出的目标直方图,一个二维数组
参数6:int类型的dims,需要计算的直方图维度。
参数7:const int*类型的histSize,存放多个维度的直方图尺寸的数组。
参数8:const float**类型的ranges,表示每一个维度数组(第六个参数dims)的每一维边界阵列,可以理解为每一维数值的取值范围。
参数9:bool类型的uniform,指示直方图是否均匀的标识符
参数10:bool类型的accumulate,累计标识符,有默认值false.
*/
minMaxLoc
功能:在数组中找到全局最小值和最大值。如果数组是二维的,可以返回最小位置和最大位置。
总结
参考链接
【OpenCV】数字图像灰度直方图
OpenCV从入门到放弃(七):直方图那些事儿
《学习OpenCV》第7章 直方图与匹配