灰度直方图是数字图像中最简单且有用的工具,这一篇主要总结OpenCV中直方图CvHistogram的结构和应用。
灰度直方图的定义
灰度直方图是灰度级的函数,描述图像中该灰度级的像素个数(或该灰度级像素出现的频率):其横坐标是灰度级,纵坐标表示图像中该灰度级出现的个数(频率)。
一维直方图的结构表示为
高维直方图可以理解为图像在每个维度上灰度级分布的直方图。常见的是二维直方图。如红-蓝直方图的两个分量分别表示红光图像的灰度值和蓝光图像灰度值的函数。其图像坐标(Dr,Db)处对应在红光图像中具有灰度级Dr同时在蓝光图像中具有灰度级Db的像素个数。这是基于多光谱——每个像素有多个变量——的数字图像,二维中对应每个像素统计个变量。
OpenCV中的直方图CvHistogram
注意我们在上面理解直方图的意义时更多把他想象成一幅“图”,继而理解图中横坐标,纵坐标的意义。而在OpenCV中,应该更多把直方图看做“数据结构”来理解。
typedef struct CvHistogram
{
int type;
CvArr* bins; //存放每个灰度级数目的数组指针
float thresh[CV_MAX_DIM][2]; //均匀直方图
float** thresh2; //非均匀直方图
CvMatND mat; //直方图数组的内部数据结构
}
CvHistogram;
这个结构看起来简单(比IplImage*元素少多了。。。)其实并不太好理解。
第一个成员type用来指定第二个成员bins的类型。OpenCv中常见到CvArr*的接口,可以用以指定诸如CvMat、CvMatND、IplImage的类型,其实CvArr*的是一个指向void的指针。在函数内部有时需要得到确切的指向类型,这就需要type来指定。
thresh用来指定统计直方图分布的上下界。比如[0 255]表示用来统计图像中像素分别在灰度级[0 255]区间的分布情况,CV_MAX_DIM对应直方图的维数,假如设定二维红-蓝直方图的thresh为[0 255;100 200],就是分别统计红色图像灰度级在[0 255]以及蓝色图像在灰度级[100 200]的分布情况。
thresh用以指定均匀直方图的分布,我们按每个像素理解自然是“均匀分布”,其实也可以统计像素在几个区间的分布。如果统计像素在2个区间的分布,则对应[0 255]的上下界,均匀分布统计的区间即[0 127] [127 255]分布的概率,这也是为什么thresh第二个维数默认为2——会自动均分上下界;而thresh2指定非均匀的分布,这就需要指定每个区间的上下界,如果要统计直方图在区间(0,10,100,255)的分布,那需要指定thresh2的一个维度为[0 10 100 255],所以用float**形式表示。
mat简单说就是存储了直方图的信息,即我们统计的直方图分布概率。
创建直方图 cvCreateHist()
OpenCV中用cvCreateHist()创建一个直方图:
CvHistogram* cvCreateHist(
int dims, //直方图维数
int* sizes,//直翻图维数尺寸
int type, //直方图的表示格式
float** ranges=NULL, //图中方块范围的数组
int uniform=1 //归一化标识
);
size数组的长度为dims,每个数表示分配给对应维数的bin的个数。如dims=3,则size中用[s1,s2,s3]分别指定每维bin的个数。
type有两种:CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组 CvMatND; CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组 CvSparseMat。
ranges就是那个复杂的不好理解的thresh的范围,他的内容取决于uniform的值。uniform为0是均匀的,非0时不均匀。
计算图像直方图的函数为CalcHist():
void cvCalcHist(
IplImage** image, //输入图像(也可用CvMat**)
CvHistogram* hist, //直方图指针
int accumulate=0, //累计标识。如果设置,则直方图在开始时不被清零。
const CvArr* mask=NULL //操作 mask, 确定输入图像的哪个象素被计数
);
要注意的是这个函数用来计算一张(或多张)
单通道图像的直方图,如果要计算多通道,则用这个函数分别计算图像每个单通道。
实践:一维直方图
下面实践一下用OpenCV生成图像的一维直方图
int main( )
{
IplImage * src= cvLoadImage("baboon.jpg");
IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,gray_plane,CV_BGR2GRAY);
int hist_size = 256; //直方图尺寸
int hist_height = 256;
float range[] = {0,255}; //灰度级的范围
float* ranges[]={range};
//创建一维直方图,统计图像在[0 255]像素的均匀分布
CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
//计算灰度图像的一维直方图
cvCalcHist(&gray_plane,gray_hist,0,0);
//归一化直方图
cvNormalizeHist(gray_hist,1.0);
int scale = 2;
//创建一张一维直方图的“图”,横坐标为灰度级,纵坐标为像素个数(*scale)
IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height),8,3);
cvZero(hist_image);
//统计直方图中的最大直方块
float max_value = 0;
cvGetMinMaxHistValue(gray_hist, 0,&max_value,0,0);
//分别将每个直方块的值绘制到图中
for(int i=0;i<hist_size;i++)
{
float bin_val = cvQueryHistValue_1D(gray_hist,i); //像素i的概率
int intensity = cvRound(bin_val*hist_height/max_value); //要绘制的高度
cvRectangle(hist_image,
cvPoint(i*scale,hist_height-1),
cvPoint((i+1)*scale - 1, hist_height - intensity),
CV_RGB(255,255,255));
}
cvNamedWindow( "GraySource", 1 );
cvShowImage("GraySource",gray_plane);
cvNamedWindow( "H-S Histogram", 1 );
cvShowImage( "H-S Histogram", hist_image );
cvWaitKey(0);
}
试验结果:
对应的,我们可以用一样的思路统计每个通道的直方图,并绘制图像每个通道像素的分布:
实践:二维直方图
我们也可以结合OpenCV的例子生成二维直方图:
IplImage* r_plane = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* g_plane = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* b_plane = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* planes[] = { r_plane, g_plane };
//将HSV图像分离到不同的通道中
cvCvtPixToPlane( src, b_plane, g_plane, r_plane, 0 );
// 生成二维直方图数据结构
int r_bins =256, b_bins = 256;
CvHistogram* hist;
{
int hist_size[] = { r_bins, b_bins };
float r_ranges[] = { 0, 255 }; // hue is [0,180]
float b_ranges[] = { 0, 255 };
float* ranges[] = { r_ranges,b_ranges };
hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1);
}
//计算一张或多张单通道图像image(s) 的直方图
cvCalcHist( planes, hist, 0, 0 );
刚才的图我们是对应每个横坐标绘制纵坐标的直方块,二维的图需要绘制每个点:
for( int h = 0; h < r_bins; h++ ) {
for( int s = 0; s < b_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);
}
}
最终生成二维直方图:
直方图的应用以后再讨论。
Mat格式的参考这里:
分享到:
相关推荐
基本包含数字图像的所有常见的预处理方法,OStu二值化方法,灰度增强,直方图均衡化等
基于opencv2做的图像处理程序,实现了冈萨雷斯那本著名的《数字图像处理》中的一些算法,目前已提供的包括:对比度拉伸变换,直方图均衡化,直方图匹配变换,灰度变换,对数变换,伽马变换等。
绘制灰度直方图、直方图均衡、对比度调节、几何变换、图片加噪声、高斯噪声、椒盐噪声、周期噪声、均值去噪、中值去噪、高通滤波、低通滤波
并使用界面制作工具(PyQt、PySide等)设计软件界面,对处理前后的图像以及直方图等进行对比显示;将实验结果与其他软件实现的效果进行比较、分析。 本资源实现了总共30多种的功能函数,同时含有PyQt5界面以及动态...
基于Qt开发的OpenCV数字图像处理工具箱包括畸变处理+ROI+预处理+分割等+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 项目简介: 畸变矫正 a) ...
用OpenCV实现的图像处理软件,实现了 图像信息(直方图,灰度图)图像的几何变换(放缩,翻转,旋转)图像增强(直方图均衡化,拉普拉斯锐化,高斯低通滤波,霍夫变换)图像复原(加噪去噪)图像分割(边缘检测,...
采用C++语言和OpenCV(版本不限)来实现直方图规定化,可以完成输入图像到目标图像的风格迁移和转变。
基于OpenCV+Eigen3 + C++完成的数字图像处理+遥感应用作业源码+项目说明(遥感图像读取,大气校正等).zip 【资源包含作业内容】 半经验C值实现地形校正 几何校正: 使用SIFT特征点提取与匹配 二次多项式模型 重采样...
实现了数字图像的直方图均衡处理。 实验环境:c++、opencv+vs2017 博文地址:https://blog.csdn.net/C2681595858/article/details/82869787
一种基于纹理特征提取的图像检索,描述了纹理和纹理特征,介绍了几种常用的纹理分析方法,有灰度直方图、边缘方向直方图、空间灰度共生矩阵、Tamura 纹理特征、Gabor 滤波器和小波以及图像纹理谱分析方法,本文在传统...
如 OpenCV 、 Qt 来制作,实现了打开图像文件、显示图像、存储处理后图像,对图像进行灰度化、二值化(阈值可调)、3×3 均值滤波、3×3 中值滤波、拉普拉斯 4 领域锐化、边缘检测、直方图计算与显示功能;...
使用OpenCV / C ++进行数字图像处理 色彩变换 将彩色图像转换为灰度图像 将灰度图像转换为彩色图像 将图像从RGB转换为HSV彩色系统 将图像从HSV颜色空间转换为RGB颜色系统 增加或减少图像的亮度 增加或减少图像的对比...
9.1.1 灰度直方图 326 9.1.2 基本原理 328 9.1.3 编程实现 328 9.2 灰度线性变换 338 9.2.1 基本原理 338 9.2.2 编程实现 341 9.3 灰度非线性变换 344 9.3.1 灰度对数变换 344 9.3.2 灰度幂次变换 350 9.3.3 灰度...
数字图像处理中一些简单的操作,OpenCV配置,主要功能实现显示、放缩,几何变换,傅里叶变换、滤波器等
常见的特征提取方法包括直方图、边缘检测、轮廓提取等。 模型训练: 使用机器学习算法或深度学习框架(如TensorFlow、PyTorch)训练一个手写数字识别模型。你可以选择K邻近、支持向量机、决策树等传统机器学习算法...
灰度直方图对比均衡化归一化,矩阵变换操作节约时间 空间域低通高通中值滤波,一共四种不同的操作 频域上高斯低通和高通滤波 一二级算子一共四种对比效果 所有代码都是自己的手动实现,并没有调用opencv库,适合初学...
(3)实现基于直方图均衡化的图像增强,包括灰度图像和彩色图像。 实验三 数字图像的形态学处理及边缘检测 1.用 OpenCV 实现数字图像的形态学运算,提取图像分量信息最本质的形状特征,不同运算操作的能实现的目的;...
如 OpenCV 、 Qt 来制作,实现了打开图像文件、显示图像、存储处理后图像,对图像进行灰度化、二值化(阈值可调)、3×3 均值滤波、3×3 中值滤波、拉普拉斯 4 领域锐化、边缘检测、直方图计算与显示功能;...
本数字图像处理软件设计基于Python、opencv、PyQt,其中涵盖图像增强(直方图均衡化与直方图规定化)、图像空间域卷积滤波、波段运算(中缀转后缀计算并有效处理NAN等计算异常)、重采样(最近邻、双线性内插、三次...
基于python环境以及opencv的前提下,对图像进行处理,涉及到统计灰度级像素点数、幂律变换、双线性插值放大缩小、直方图均衡化处理并显示、均值滤波、拉普拉斯算子和Sobel算子等处理操作。