首页 > 学院 > 开发设计 > 正文

opencv学习笔记(二十六)直方图有关的操作

2019-11-08 02:19:06
字体:
来源:转载
供稿:网友

直方图匹配

在分析图像、物体和视频信息的过程中,我们常常想把眼中看到的对字用直方图(histogram)表示。直方图可以用来描述各种不同的事情,如物体的色彩分布、物体边缘梯度模板,以及表示目标位置的当前假设(目标当前位置的假设)的概率分布。直方图广泛应用于很多计算机视觉应用中。通过标记帧与帧之间显著的边缘和颜色的统计变化,直方图被用来检测视频中场景的变换。通过为每个兴趣点设置一个有相近特征的直方图所构成的“标签”,用以确定图像中的兴趣点。边缘、色彩、角等直方图构成了可以被传递给目标识别分类器的一个通用特征类型。色彩和边缘的直方图序列还可以用来识别网络视频是否被复制等。直方图是计算机视觉中最经典的工具之一。 简单地说,直方图就是对数据进行统计,将统计值组织到一系列事先定义好的bin中。bin中的数值是从数据中计算出的特征的统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。无论如何,直方图获得的是数据分布的统计图。通常直方图的维数要低于原始数据。

bin

“组距”的意思。 例如:计算颜色直方图需要将颜色空间划分为若干小的颜色区间,即直方图的bin,通过计算颜色在每个小区间内德像素得到颜色直方图,bin越多,直方图对颜色的分辨率越强,但增加了计算机的负担。

直方图的基本数据结构

首先直接查看CvHistogram的数据结构。

typedef struct CvHistogram{ int type; CvArr* bins; float thresh[CV-MAX-DIM][2]; for uniform histograms float** thresh2; for nonuniform histograms CvMatND mat; embedded matrix header for array histograms}CvHistogram;

这个定义看起来很简单但并非如此,因为直方图的很多内部数据都被存储于CvMatND结构中。我们用下面的程序创建一个新的直方图:

创建直方图cvCreateHist()

定义: CvHistogram* cvCreateHist( int dims, int* sizes, int type, float** ranges=NULL, int uniform=1 ); 参数: dims 直方图维数的数目 sizes 直方图维数尺寸的数组 自己的理解: 比如创建一维直方图,你设置size是256,就代表直方图横坐标是这个值。假如你的range是0~255,那么每组分到的宽度是1;假如size设置成256*2,那么假如你的range是0~255,那么每组分到的宽度是2。反正,设置的越大每组的宽度就越大。 type 直方图的表示格式: CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组 CvMatND; CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组CvSparseMat.

ranges 图中方块范围的数组。它的内容取决于参数 uniform 的值。这个范围的用处是确定何时计算直方图或决定反向映射(backPRojected ),每个方块对应于输入图像的哪个/哪组值。 uniform 归一化标识 按照我自己的理解就是: 如果不为0,bin均匀;为0,看ranges怎么设置。

cvSetHistBinRanges()

作用:在使用直方图之前给rangs设置数值。 定义: void cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform=1 ); 参数: cvSetHistRanges()中的变量与cvCreateHist()中的相应变量完全一致。如果想重用直方图,可以对其进行清零操作(即设置所有bins为0),或者使用通常的释放函数释放直方图。

直方图清零cvClearHist()

void cvClearHist( CvHistogram* hist );

释放直方图cvReleaseHist()

void cvReleaseHist( CvHistogram**hist ); 通常,这些释放函数通过一个指针被调用,该指针指向一个直方图的指针,后者取自创建直方图的函数。一旦直方图被释放,直方图指针便被设置为NULL。

从数组中创建直方图cvMakeHistHeaderForArray()

定义: CvHistogram* cvMakeHistHeaderForArray( int dims, int* sizes, CvHistogram* hist, float* data, float** ranges=NULL, int uniform=1 ); 参数: hist是指向CvHistogram数据结构的指针; data用来存储直方块的数组。是指向存储直方图bins的大小为sizes[0]sizes[1]…*sizes[dim-1]的区域的指针。注意,data是浮点数指针,因为直方图的内部数据类型描述永远是浮点数。返回值与我们输入的hist值一样。 与cvCreateHist()程序不同,没有type变量。所有由cvMakeHistHeaderForArray()创建的直方图都是密集直方图。 最后一点:由于(假设)为直方图的bins分配了数据存储空间,则没有理由为CvHistogram结构再次调用cvReleaseHist()。你只需要清除头结构(如果没有在堆栈中分配它),当然,也要清除你自己创建的数据;但是,由于这些变量是你自己定义的,你应该用自己的方式处理它们。 就是说: 函数 cvMakeHistHeaderForArray 初始化直方图,其中头和直方块为用户所分配以后不需要调用 cvReleaseHist。

查询直方块的值cvQueryHistValue_1D~ND()

double cvQueryHistValue_1D( CvHistogram* hist, int idx0 ); double cvQueryHistValue_2D( CvHistogram* hist, int idx0, int idx1 ); double cvQueryHistValue_3D( CvHistogram* hist, int idx0, int idx1, int idx2 ); double cvQueryHistValue_nD( CvHistogram* hist, int idxN );

返回直方块的指针cvGetHistValue_1D~ND()

每个函数都返回相应bin中的值的浮点数。同样地,可以利用函数返回的bin的指针(不是bin的值)来设置(或者获得)直方图的bin的值。 float* cvGetHistValue_1D( CvHistogram* hist, int idx0 ); float* cvGetHistValue_2D( CvHistogram* hist, int idx0, int idx1 ); float* cvGetHistValue_3D( CvHistogram* hist, int idx0, int idx1, int idx2 ); float* cvGetHistValue_nD( CvHistogram* hist, int idxN ); 这些函数与cvGetReal D和cvPtr*D等系列函数非常相似,事实上,它们几乎相同。在函数里传入的矩阵hist->bins被调用的方式本质上与其被直接的矩阵访问模式是一样的。类似地,稀疏直方图函数继承了它所对应的稀疏矩阵函数的一些行为。在稀疏直方图中,如果想利用函数GetHist()来访问不存在的bin,这个不存在的bin会被自动创建,并且其值被设为0。 注意,函数QueryHist*()不会创建不存在的bin。

归一化直方图cvNormalizeHist()

cvNormalizeHist(CvHistogram* hist,double factor); factor——归一化因子; 这里的hist表示直方图,factor表示直方图归一化后的数值(通常情况下设为1)。注意,factor是一个double类型的数据,尽管函数CvHistogram( )的内部数据类型通常都是float——这进一步说明了OpenCV是一个不断改进的项目! 函数 cvNormalizeHist 通过缩放来归一化直方块,使得所有块的和等于 factor。

对直方图取阈值cvThreshHist()

cvThreshHist(CvHistogram* hist,double factor); 作用: 函数 cvThreshHist 清除那些小于指定阈值的直方块。 书上的说法: 变量factor是一个开关阈值。进行直方图阈值化处理之后,小于给定阈值的各个bin的值都被设为0。回忆图像阈值函数cvThreshold(),直方图阈值函数与参数threshold_type设置为CV_THRESH_ TOZERO的图像阈值函数类似。不幸的是,没有方便的直方图阈值函数来提供其他threshold类型的类似操作。然而,实际上函数cvThreshHist()或许是最常用的函数,因为我们在使用实数类型数据的时候常常将包含极少数据点的bin去除掉。这些bins通常是噪声,因此将这些bins的值设为0。

拷贝直方图cvCopyHist()

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

直方图中最小值和最大值cvGetMinMaxHistValue()

定义: void cvGetMinMaxHistValue( const CvHistogram* hist, float* min_value,//直方图最小值的指针 float* max_value,//直方图最大值的指针 int* min_idx=NULL,//数组中最小坐标的指针 int* max_idx=NULL//数组中最大坐标的指针 ); 函数 cvGetMinMaxHistValue 发现最大和最小直方块以及它们的位置。任何输出变量都是可选的。在具有同样值几个极值中,返回具有最小下标索引(以字母排列顺序定)的那一个。

计算图像( Image )的直方图cvCalHist()

对于多通道图像(如HSV或RGB),在调用函数cvCalcHist()之前,先要用函数cvSplit ( )将图像分为单通道的。这诚然有点痛苦,但是应该考虑到多个图像通道很常见,它们常常包含一个图像的不同过滤形态,如梯度通道、YUV中的U或V通道。可以想像,如果试图处理包含多通道的多个图像,情形将有多么混乱(需要确定谁在哪儿用这些图像的哪个通道)。为了避免这种混淆,所有传递给cvCa1Hist()的图像都被假设(或被要求)为单通道图像。 void cvCalcHist( iplImage** image, CvHistogram* hist, int accumulate=0, const CvArr* mask=NULL ); 参数: image 输入图像(虽然也可以使用 CvMat** ). hist 直方图指针 accumulate 累计标识。如果非0,则直方图在开始时不被清零。这个特征保证可以为多个图像计算一个单独的直方图,或者在线更新直方图。此外,它允许被cvCalHist()在一个数据采集循环中被多次调用。 mask 是一个可选的布尔变量,如果被设为非NULL,则只有与mask非0元素对应的像素点会被包含在计算直方图中。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表