最终效果(完整代码在最后):
图片的直方图
原图:
均衡化后的图片:
什么是灰度直方图?
灰度直方图(histogram)是灰度级的函数,描述的是图像中每种灰度级像素的个数,反映图像中每种灰度出现的频率。横坐标是灰度级,纵坐标是灰度级出现的频率。
对于连续图像,平滑地从中心的高灰度级变化到边缘的低灰度级。直方图定义为:
其中A(D)为阈值面积函数:为一幅连续图像中被具有灰度级D的所有轮廓线所包围的面积。对于离散函数,固定ΔD为1,则:H(D)=A(D)-A(D+1)
色彩直方图是高维直方图的特例,它统计色彩的出现频率,即色彩概率分布信息。
通常这需要一定的量化过程,将色彩分成若干互不重叠的种类。一般不直接在RGB色彩空间中统计,而是在将亮度分离出来后,对代表色彩部分的信息进行统计,如在HSI空间的HS子空间、YUV空间的UV子空间,以及其它反映人类视觉特点的彩色空间表示中进行。
其中直方图的计算方法如下:
依据定义,若图像具有L(通常L=256,即8位灰度级)级灰度,则大小为MxN的灰度图像f(x,y)的灰度直方图hist[0…L-1]可用如下计算获得。
1、初始化 hist[k]=0; k=0,…,L-1
2、统计 hist[f(x,y)]++; x=0,…,M-1, y =0,…,N-1
3、归一化 hist[f(x,y)]/=M*N
那么说了这么多,直方图究竟有什么作用呢?
在使用轮廓线确定物体边界时,通过直方图更好的选择边界阈值,进行阈值化处理;对物体与背景有较强对比的景物的分割特别有用;简单物体的面积和综合光密度IOD可以通过图像的直方图求得。
一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征。图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。
图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。打个比方就是 这张图中属于255这个灰度级,那么整张图片中255出现的次数就是255出现的频率。
要实现绘制直方图首先需要每个图片中每个灰度级出现的次数读取出来。
这个用到的是 opencv 中的自带的函数cv2.imread(filepath)
,读取出来的数据是一个 numpy.ndarray 的矩阵,其中就是每个灰度级出现的次数。
之后,我们要做的就是将每个灰度级出现的次数统计出来,这里我使用了一个循环遍历然后通过 count 来数出每个灰度级出现的次数。之后读取出来以后就是类似于一个字典的形式,前面的key是灰度级,后面的value就是这个灰度级出现的次数。
注意:因为一张图片不一定包含 0-255 所有的灰度级,所以需要再次设置一个从 0-256 的循环来进行遍历,没有的将这个灰度级也加入,并将他的 value 设置为0
#计算灰度图的直方图
def clczhifangtu(gray) :
hist_new = []
num = []
hist_result = []
hist_key = []
gray1 = list(gray.ravel()) #将读取出来的数组转化为一维列表方便循环遍历
obj = dict(collections.Counter(gray1)) #计算每个灰度级出现的次数
obj = sorted(obj.items(),key=lambda item:item[0])
for each in obj :
hist1 = []
key = list(each)[0]
each =list(each)[1]
hist_key.append(key)
hist1.append(each)
hist_new.append(hist1)
#检查从0-255每个通道是否都有个数,没有的话添加并将值设为0
for i in range (0,256) :
if i in hist_key :
num = hist_key.index(i)
hist_result.append(hist_new[num])
else :
hist_result.append([0])
if len(hist_result) < 256 : #检查循环后的列表中是不是已经包含所有的灰度级
for i in range (0,256-len(hist_result)) :
hist_new.append([0])
hist_result = np.array(hist_result)
return hist_result
计算均衡化的的原理就不细说了,直接上代码
#计算均衡化
def clcresult(hist_new ,lut ,gray) :
sum = 0
Value_sum = []
hist1 = []
binValue = []
for hist1 in hist_new :
for j in hist1:
binValue.append(j)
sum += j
Value_sum.append(sum)
min_n = min(Value_sum)
max_num = max(Value_sum)
# 生成查找表
for i, v in enumerate(lut):
lut[i] = int(254.0 * Value_sum[i] / max_num + 0.5)
# 计算
result = lut[gray]
return result
灰度图处理代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
import collections
#计算灰度图的直方图
def clczhifangtu(gray) :
hist_new = []
num = []
hist_result = []
hist_key = []
gray1 = list(gray.ravel())
obj = dict(collections.Counter(gray1))
obj = sorted(obj.items(),key=lambda item:item[0])
for each in obj :
hist1 = []
key = list(each)[0]
each =list(each)[1]
hist_key.append(key)
hist1.append(each)
hist_new.append(hist1)
#检查从0-255每个通道是否都有个数,没有的话添加并将值设为0
for i in range (0,256) :
if i in hist_key :
num = hist_key.index(i)
hist_result.append(hist_new[num])
else :
hist_result.append([0])
if len(hist_result) < 256 :
for i in range (0,256-len(hist_result)) :
hist_new.append([0])
hist_result = np.array(hist_result)
return hist_result
#计算均衡化
def clcresult(hist_new ,lut ,gray) :
sum = 0
Value_sum = []
hist1 = []
binValue = []
for hist1 in hist_new :
for j in hist1:
binValue.append(j)
sum += j
Value_sum.append(sum)
min_n = min(Value_sum)
max_num = max(Value_sum)
# 生成查找表
for i, v in enumerate(lut):
lut[i] = int(254.0 * Value_sum[i] / max_num + 0.5)
# 计算
result = lut[gray]
return result
def main() :
image = cv2.imread(r'D:\Code\Python\1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 创建空的查找表
lut = np.zeros(256, dtype=gray.dtype)
#直方图转化
hist_new = clczhifangtu(gray)
#并绘制直方图
plt.plot(hist_new)
plt.show()
result = clcresult(hist_new,lut,gray)
cv2.imshow('yuantu',gray)
cv2.imshow("Result",result)
cv2.waitKey(0)
cv2.destroyAllWindows()
main()
彩色图和灰度图处理类似,不过要把彩色图的三个通道分开单独处理,之后在合并即可
import cv2
import numpy as np
import matplotlib.pyplot as plt
import collections
def clczhifangtu(gray):
# 计算彩色图单通道的直方图
hist_new = []
num = []
hist_result = []
hist_key = []
gray1 = list(gray.ravel())
obj = dict(collections.Counter(gray1))
obj = sorted(obj.items(),key=lambda item:item[0])
for each in obj :
hist1 = []
key = list(each)[0]
each =list(each)[1]
hist_key.append(key)
hist1.append(each)
hist_new.append(hist1)
for i in range (0,256) :
if i in hist_key :
num = hist_key.index(i)
hist_result.append(hist_new[num])
else :
hist_result.append([0])
if len(hist_result) < 256 :
for i in range (0,256-len(hist_result)) :
hist_new.append([0])
hist_result = np.array(hist_result)
return hist_result
#单通道均衡化
def clcresult(hist_new, lut, gray):
sum = 0
Value_sum = []
hist1 = []
binValue = []
for hist1 in hist_new:
for j in hist1:
binValue.append(j)
sum += j
Value_sum.append(sum)
min_n = min(Value_sum)
max_num = max(Value_sum)
# 生成查找表
for i, v in enumerate(lut):
lut[i] = int(254.0 * Value_sum[i] / max_num + 0.5)
# 计算
result = lut[gray]
return result
#获取红色通道:
def get_red(img):
redImg = img[:, :, 2]
return redImg
#获取绿色通道:
def get_green(img):
greenImg = img[:, :, 1]
return greenImg
#获取蓝色通道
def get_blue(img):
blueImg = img[:, :, 0]
return blueImg
def main():
image = cv2.imread(r'D:\Code\Python\2.jpg')
# 创建空的查找表
lut = np.zeros(256, dtype=image.dtype)
b = get_blue(image)
g = get_green(image)
r = get_red(image)
hist_new_b = clczhifangtu(b)
hist_new_g = clczhifangtu(g)
hist_new_r = clczhifangtu(r)
#绘制直方图
plt.plot(hist_new_b, color='b')
plt.plot(hist_new_g, color='g')
plt.plot(hist_new_r, color='r')
plt.show()
result_b = clcresult(hist_new_b, lut, b)
result_g = clcresult(hist_new_g, lut, g)
result_r = clcresult(hist_new_r, lut, r)
#合并通道
result = cv2.merge((result_b, result_g, result_r))
cv2.imshow('yuantu', image)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
main()
原图
均衡化后