【数字图像处理】直方图Histogram

DIP直方图的C++实现

Posted by Raserting_L on July 18, 2019

开篇介绍

最近在利用晚上在寝室的22:00-23:00之间的时间学习数字图像处理的(DIP),主要是以冈萨雷斯第三版版数字图像处理为教材,以电子科大的DIP视频为辅助,经过一段时间的学习,还是大有收获,弄懂了之前做深度学习图像处理时的一些存在的疑问(说来惭愧,当时直接上的机器学习深度学习,使用OpenCV框架,所以虽然对卷积什么的有所耳闻并且使用次数还不少,但是对于其中的一些原理,却不是很了解。现在再来学习基础,希望为时不晚。)。今天空余时间想着把最近学的直方图,图像平滑处理、锐化等图像增强操作,图像频域操作用C++来实现一遍。毕竟代码这种东西要多写写,熟能生巧嘛。

直方图意义

简单点做一个类比:比如我们有十种颜色的球,每种颜色的球有不同的数量,假设颜色分布为a0-a9,数量为n(x)(x取值为a0-a9)那么直方图就是以a0~a9为横坐标,n为纵坐标的统计直方图。

如果将得到的直方图数据归一化(每个分量除以球数总和),也就是使得各分量总和为1,各个分量就表示这种颜色的球出现的频率,就得到频率直方图。 如果将各种颜色换成各灰度值,球的个数等效的换成具有该灰度的像素数量,或者换成该灰度出现的频率,就成了图像的直方图,对于彩色图像和灰度图像,直方图具有重要的统计意义,而对于二值图像来说,该意义不大,因为二值图像就两个灰度,所以其只能反映黑白面积比例。 直方图均衡的目的是为了使灰度分布的更广泛,从而来拉伸对比度。

如果我们需要得到直方图,那就需要对图像进行遍历,统计每一个灰度值所对应的像素点个数,实现代码如下:

//直方图初始化操作
void initHistogram(int *hist){
	for(int i = 0 ; i < GRAY_LEVEL ; i++){
		hist[i] = 0 ;
	}
}

//获得图片对应直方图
void GetHistogram(double *src, int *hist, int width, int height){
	initHistogram(hist) ;
	for(int i = 0 ; i < height ; i++ ) {
		for(int j = 0 ; j < width ; j++ ){
			int temp = src[i*width + j] ;
			hist[temp] ++ ;
		}
	}
}

直方图均衡化

一般如果一个图像几乎所有的像素值都对应某几个邻近的灰度值,那这样整个图像会呈现出趋于一种颜色视觉感,视觉感受不太好,这个时候使用直方图均衡化可能(注意,不是一定,有些情况效果并且不好,书中有这个举例)会增强其对比度然后让图像更清晰。

实际操作就是:n个灰度值,每个灰度值都对应一个频率$p_r(r_n)$, 再对于每个灰度值计算出他自己以及所有标号小于他的灰度值的频率之和:$\sum_{j=0}^{n}p_r(r_j)$ ,然后该灰度值在直方图均衡化之后对应的灰度值为最大的灰度值数乘该频率之和:比如如果总共灰度值范围是0-255,那对应的灰度值就是$255 * \sum_{j=0}^{n}p_r(r_j)$

最后得到的代码如下:

//直方图均衡化
void HistogramEqualization(double *src, int *dst_map, int width, int height){
	int total = 0 ;
	int *hist = new int[GRAY_LEVEL] ;
	GetHistogram(src, hist, width, height) ;

	int *Temp_hist = new int[GRAY_LEVEL] ;
	initHistogram(Temp_hist) ;

	Temp_hist[0] = hist[0] ; 
	total = hist[0] ;

	for(int i = 1 ; i < GRAY_LEVEL ; i ++){
		Temp_hist[i] = Temp_hist[i - 1] + hist[i] ;
		total += hist[i] ;
	}

	for(int i = 0 ; i < GRAY_LEVEL ; i++ ){
		dst_map[i] = (int)((GRAY_LEVEL - 1) * ((double)Temp_hist[i] / (double)total)) ;
	}
}

另外还有直方图匹配(规定化),也就是让直方图的灰度值频率分布按照自己定的来,具体的可以去看书啦,今天就总结到这,完整代码我会放在我的github上,右边有链接哟。