一,直方图的绘制
1.直方图的概念:
在图像处理中,经常用到直方图,如颜色直方图、灰度直方图等。
图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所
占的多少。
图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横
坐标是灰度级,纵坐标是该灰度级出现的频率。
(简洁来说:就是描述图像中各个灰度级的个数)
直方图反映了图像中的灰度分布规律。它描述每个灰度级具有的像素个数,但不包含
这些像素在图像中的位置信息。
图像直方图不关心像素所处的空间位置,因此不受图像旋转和平移变化的影响,可以作为图像的特征。
2.直方图的应用:
直方图的应用主要体现在来表现图像是否过亮或过暗,而解决的办法就是直方图均值化。
3.代码实现:
- 头文件:
import cv2
import numpy as np
from matplotlib import pyplot as plt
- 灰度图像直方图绘制:
- plt接口实现:
# 获取灰度图像 img = cv2.imread("lenna.png", 1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #cv2.imshow("image_gray", gray)# 灰度图像的直方图,方法一 plt.figure() plt.hist(gray.ravel(), 256) plt.show()
- opencv接口实现:
''' equalizeHist—直方图均衡化 函数原型: equalizeHist(src, dst=None) src:图像矩阵(单通道图像) dst:默认即可 '''# 灰度图像的直方图, 方法二 hist = cv2.calcHist([gray],[0],None,[256],[0,256]) plt.figure()#新建一个图像 plt.title("Grayscale Histogram") plt.xlabel("Bins")#X轴标签 plt.ylabel("# of Pixels")#Y轴标签 plt.plot(hist) plt.xlim([0,256])#设置x坐标轴范围 plt.show()
- plt接口实现:
- 彩色图像直方图绘制:
#彩色图像直方图image = cv2.imread("lenna.png")
cv2.imshow("Original",image)
#cv2.waitKey(0)chans = cv2.split(image) #把图像维度切割
colors = ("b","g","r")
plt.figure()
plt.title("Flattened Color Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")for (chan,color) in zip(chans,colors):hist = cv2.calcHist([chan],[0],None,[256],[0,256])plt.plot(hist,color = color)plt.xlim([0,256])
plt.show()
4.实现结果:
二,直方图均衡化
1.直方图均衡化的概念:
直方图均衡化是将原图像的直方图通过变换函数变为均匀的直方图,然后按均匀直方图修改原
图像,从而获得一幅灰度分布均匀的新图像。
直方图均衡化就是用一定的算法使直方图大致平和的方法
直方图均衡化的作用是图像增强
注意:能适当提升图像的对比度
2.直方图均衡化的思想:
为了将原图像的亮度范围进行扩展,需要一个映射函数,将原图像的像素值均衡映射到新直
方图中,这个映射函数有两个条件:
- 为了不打乱原有的顺序,映射后亮、暗的大小关系不能改变,
- 映射后必须在原有的范围内,比如(0-255)
实现步骤:
- 依次扫描原始灰度图像的每一个像素,计算出图像的灰度直方图H
- 计算灰度直方图的累加直方图
- 根据累加直方图和直方图均衡化原理得到输入与输出之间的映射关系。
- 最后根据映射关系得到结果:dst(x,y) = H’(src(x,y))进行图像变换
映射关系的推导:(在实际应用中采用接口调用即可)
- 对于输入图像的任意一个像素p, p∈[0,255], 总能在输出图像里有对应的像素q, q∈[0,255] 使得下面等式成立(输入和输出的像素总量相等):
- 其中,输出图像每个灰度级的个数:
H和W代表图像的长和宽,HW就是指图像中存在的像素点个数* - 代入累加直方图公式:
(q+1)是指从0到q有q+1个值
最后的结果就是红色框的公式!
不过这里要注意:在运算后的q可能是负数,如果要手动实现该算法,这里要处理一下
3.直方图均衡化的实现举例:
首先要我们要明确:替换前和替换后的像素值的映射关系如下:
最开始,我们需要均衡化的图像中的像素值如下:
很明显看出来,这个图像是5*5的图像,像素值最高是9,最低是0。
接下来,我们建立一个表格:
pix值:是指图像中包含所有的像素值:该图像是从0-9。
Ni值:是该pix像素值存在的个数,在目标图像中,0像素有3个,Ni值就为3。
Pi值:是该像素值的概率。
sunmPi值就是之前Pi的总和,也可以看作sumPi=Pi+sumP(i-1),比如sumP0=P0=0.12,sumP1=sumP0+P1
最后的结果就是sumPi×255-1,最后将这个结果四舍五入后的数值替换原像素数值。
4.代码实现:
- 头文件
import cv2
import numpy as np
from matplotlib import pyplot as plt
- 灰度图像直方图均衡化
'''
equalizeHist—直方图均衡化
函数原型: equalizeHist(src, dst=None)
src:图像矩阵(单通道图像)
dst:默认即可
'''# 获取灰度图像
img = cv2.imread("lenna.png", 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #转换成灰色图像
#cv2.imshow("image_gray", gray)# 灰度图像直方图均衡化
dst = cv2.equalizeHist(gray)# 直方图
hist = cv2.calcHist([dst],[0],None,[256],[0,256])plt.figure()
plt.hist(dst.ravel(), 256)
plt.show()cv2.imshow("Histogram Equalization", np.hstack([gray, dst]))
cv2.waitKey(0)
- 彩色图像直方图均衡化
# 彩色图像直方图均衡化
img = cv2.imread("lenna.png", 1)
cv2.imshow("src", img)# 彩色图像均衡化,需要分解通道 对每一个通道均衡化
(b, g, r) = cv2.split(img)
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
# 合并每一个通道
result = cv2.merge((bH, gH, rH))
cv2.imshow("dst_rgb", result)cv2.waitKey(0)
5.实现结果:
结果对比很明显发现在直方图中像素值变的均匀很多,而且明显均衡化的图像的对比度更高。