type
Post
status
Published
date
Nov 24, 2022
slug
image_process_2
summary
直方图(Histogram)是一种对数据分布情况的图形表示,是一种二维统计图表,它的两个坐标分别是统计样本和该样本对应的某个属性的度量,以长条图(bar)的形式具体表现。因为直方图的长度及宽度很适合用来表现数量上的变化,所以较容易解读差异小的数值。
tags
图像处理
OpenCV
Python
category
图像处理
icon
password
Property
Nov 24, 2022 12:26 PM
直方图(Histogram)是一种对数据分布情况的图形表示,是一种二维统计图表,它的两个坐标分别是统计样本和该样本对应的某个属性的度量,以长条图(bar)的形式具体表现。因为直方图的长度及宽度很适合用来表现数量上的变化,所以较容易解读差异小的数值。

标准直方图的绘制

对于任意一辐图像(这里以灰度图为例),灰度的层级范围是[0,255],它的直方图是离散函数
$$ h(r_k)=n_k $$
其中,$r_k$是第$k$级灰度值,$n_k$是图像中灰度为$r_k$的像素个数。
通常使用乘积$MN$表示图像的像素总数,$M$和$N$是图像的行和列的维数,因此,我们可以使用$MN$除它的每个分量来归一化直方图,这样归一化后的直方图可以表示为
$$ p(r_k)=\frac{n_k}{MN} $$
由此,可以看出$p(r_k)$是灰度级$r_k$在图像中出现的概率的一个估计。归一化直方图的所有分量之和等于1。

代码实现

def drawGrayHist(image): canvas = np.ones([200,256,3],dtype=np.uint8) * 255 ori_hist = [np.sum(image == i) for i in range(256)] h_bar = (ori_hist / np.max(ori_hist) * 199).astype(np.uint8).ravel() for l in range(canvas.shape[1]): canvas[199-h_bar[l]:,l] = [255,0,0] cv2.imwrite('hist_std.png',canvas)

实现效果

notion image

平滑直方图的绘制

从上面这张图可以看出,标准直方图可以很清晰地看出每一个像素的像素个数,但是相邻的几个像素变化特别剧烈,这时就需要平滑一点的直方图来表现
同样,对于任意一辐图像(以灰度图为例),灰度的层级范围是[0,255],现在把直方图的离散函数改变一下
$$ h(r_k)=\sum_{k-\delta <i< k+\delta} n_i $$
其中,$\delta$是区间的半径,$\delta$的值越大直方图约平滑

代码实现

def drawSmoothHist(image): canvas = np.ones([200,256,3],dtype=np.uint8) * 255 delta = 2 ori_hist = [np.sum(image == i) for i in range(256)] ori_hist = [sum(ori_hist[max(i-delta,0):min(256,i+delta)]) for i in range(256)] h_bar = (ori_hist / np.max(ori_hist) * 199).astype(np.uint8).ravel() for l in range(canvas.shape[1]): canvas[199-h_bar[l]:,l] = [255,0,0] cv2.imwrite('hist_smooth.png',canvas)

实现效果

notion image

多通道直方图的绘制

有的时候我们需要将图像的三个通道(以RGB为例)同时显示出来,这时只需要将三个通道的像素值分别统计出来,然后叠加在一起即可。

代码实现

def drawRGBHist(image): canvas = np.zeros([200,256,3],dtype=np.uint8) ori_hist_0 = [np.sum(image[:,:,0] == i) for i in range(256)] ori_hist_1 = [np.sum(image[:,:,1] == i) for i in range(256)] ori_hist_2 = [np.sum(image[:,:,2] == i) for i in range(256)] h_bar_0 = (ori_hist_0 / np.max(ori_hist_0) * 199).astype(np.uint8).ravel() h_bar_1 = (ori_hist_1 / np.max(ori_hist_1) * 199).astype(np.uint8).ravel() h_bar_2 = (ori_hist_2 / np.max(ori_hist_2) * 199).astype(np.uint8).ravel() for l in range(canvas.shape[1]): canvas[199-h_bar_0[l]:,l] += np.array([255,0,0],dtype=np.uint8) canvas[199-h_bar_1[l]:,l] += np.array([0,255,0],dtype=np.uint8) canvas[199-h_bar_2[l]:,l] += np.array([0,0,255],dtype=np.uint8) cv2.imwrite('hist_RGB.png',canvas)

实现效果

notion image

参考文献

  • 冈萨雷斯, 伍兹, 埃丁斯, 等. 数字图像处理: MATLAB 版[M]. 电子工业出版社, 2005.
Python图像处理专题——图形的绘制Python图像处理专题——混合模式