对于“直方图”,我想绝大部分人都不会陌生,毕竟在数学中很早就遇见过,而图像的直方图(图1),从事图像相关工作的朋友肯定是再熟悉不过了。可谓是最基础不过的知识点,也是很多种空间域处理技术的基础。
通常而言,图像的直方图都是用亮度直方图(灰度直方图)表示。对于彩色图像,还会有各个颜色通道的直方图。文中主要讲述图像的亮度直方图。它反映了图像最基本的统计特征,表示图像中具有某个灰度级的像素个数,同时也反映了图像中每种灰度出现的频率。灰度级范围为 [ 0 , L − 1 ] [0,L-1] [0,L−1]的数字图像的直方图是离散函数 h ( r k ) = n k h(r_{k})=n_{k} h(rk)=nk,其中 r k r_{k} rk是第k个灰度级的值, n k n_{k} nk是图像中的灰度 r k r_{k} rk的像素个数。若要反映灰度出现的频率,还需要做归一化操作。假设图像的长宽分别是 M M M和 N N N,则归一化的图像直方图可由离散函数 p ( r k ) = n k / M N p(r_{k})=n_{k}/MN p(rk)=nk/MN表示, p ( r k ) p(r_{k}) p(rk)则是灰度级 r k r_{k} rk在图像出现的概率估计,因此需要满足概率性质,归一化直方图的所有分量之和等于1 。可转化为如下代码
/*************************************************************************
bool histogram(BYTE* src, double* phist, int height, int width, int n)
功能: 生成直方图
参数:
src: 原始图像
phist: 输出的直方图数组
height:图像高度
width: 图像高度
n: 灰度级数(段数)
返回值: true/false
*************************************************************************/
bool histogram(BYTE* src, double* phist, int height, int width, int n=256)
{
if (n <= 0 || n > 256) return false;
// 计算分段因子
double dNumber;
memset(phist, 0, n * sizeof(double));
dNumber = 256.0 / (double)n;
// 统计直方图信息
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; i++)
{
int index = i * width + j;
BYTE pixel = src[index];
phist[(int)(pixel / dNumber)]++;
}
}
// 归一化直方图
int totalpixel = height * width;
for(int k = 0; k < n; k++)
{
phist[k] = phist[k] / totalpixel;
}
return true;
}
以上只是生成灰度直方图的方式,要显示直方图,还需要做单独的显示处理。图像直方图应用十分广泛,是十分重要的图像分析工具,在图像增强、图像分割以及图像灰度变换等图像处理过程中得到了广泛应用。
另外,因为这几年工作的缘故,发现直方图在ISP的pipeline中应用十分广泛,才有了此篇文章,用来巩固直方图相关的知识。比如Gamma、GTM、LTM等模块,会改变直方图的灰度级分布范围。AEC模块会根据亮度直方图确定当前曝光是否合理,判断当前曝光属于曝光不足、曝光正常还是曝光过度;也可以根据直方图中亮区和暗区的统计结果,确定HDR的触发条件等等。
个人声明:
以上内容,纯属个人观点,不喜勿喷。未经本人同意,不得私自转载。若文中存在纰漏,或读者有更好的建议,欢迎留言探讨。也可邮箱联系:yxyx_0212@163.com