本文主要阐述了本次作业中解决的四个问题,分别是灰度处理,直方图均衡化,直方图规定话GML,SML
一、图像预处理
1.1颜色转换意义
在图像处理过程中,我们日常的环境通常获得的是彩色图像,。一般为了减小图像原始数据量,便于后续处理时计算量更少,因为图像处理不一定需要对彩色图像的RGB三个分量都进行处理,将彩色图像转换成灰度图像。也就是3个通道(opencv中是BGR的顺序)转换成1个通道。三通道转为一通道后,运算量大大减少。
1.2灰度原理及方法
将彩色图像转换成灰度图像,也就是3个通道(RGB)转换成1个通道。 图像由彩色图转化为一般有灰度图有三种方法。分别为加权法、均值法、最大值法。
(1)加权法就是几个加权系数0.3,0.59,0.11这是根人的亮度感知系统调节出来的参数,是个广泛使用的标准化参数。
(2)均值法就是将同一个像素位置3个通道RGB的值进行平均。
(3)最大最小平均法就是取同一个像素位置的RGB中亮度最大的和最小的进行平均。
1.3灰度处理关键程序及处理结果
j
iuliang = cv2.imread("D:\\opencv_image\\jiuliang.jpg")#舍友最爱的周九良
row, col, channel = jiuliang.shape
''' 取平均法:创建与原图像行列相同的空矩阵,将三个通道进行取平均再赋值给空矩阵即可得到'''
jiuliang_gray = np.zeros((row, col))
for r in range(row):
for l in range(col):
jiuliang_gray[r, l] = 1 / 3 * jiuliang[r, l, 0] + 1 / 3 * jiuliang[r, l, 1] + 1 / 3 * jiuliang[r, l, 2]
''' 最大值最小值平均法,取图像三个通道里的最大和最小值的和求平均'''
max_jiuliang_gray = np.zeros((row, col))
for r in range ( row ):
for l in range ( col ):
max_jiuliang_gray[r, l] = 1/2* max(jiuliang[r,l, 0], jiuliang[r, l, 1], jiuliang[r, l, 2] ) + 1 / 2 * min (jiuliang[r, l, 0], jiuliang[r, l, 1], jiuliang[r, l, 2])
''' 加权平均法,取图像三个通道里的最大和最小值的和求平均'''
weight_jiuliang_gray = np.zeros((row, col))
for r in range(row):
for l in range(col):
weight_jiuliang_gray[r, l] = 0.11 * jiuliang[r, l, 0] + 0.59 * jiuliang[r, l, 1] + 0.3 * jiuliang[r, l, 2]
经实验发现 上述灰度效果相似,即使上边遍历了去尝试,但是其实python其实一句话就可以搞定
img = cv2.imread ( ‘D:\opencv_image\jiuliang.jpg’, cv2.IMREAD_GRAYSCALE)
二、 直方图均衡化
1、灰度直方图分析
灰度直方图是反映一幅图像中各灰度级像素出现的频率与灰度级的关系,以灰度级为横坐标,频率为纵坐标,绘制频率同灰度级的关系图像就是一幅灰度图像的直方图。简单地说,就是把一幅图像中每一个像素出现的次数都先统计出来,然后把每一个像素出现的次数除以总的像素个数,得到的就是这个像素出现的频率,然后再把像素与该像素出现的频率用图表示出来,就是灰度直方图。图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。
2、直方图均衡化原理
在一幅图像中,明亮图像的直方图倾向于灰度级高的一侧,灰暗图像的直方图倾向于灰度级低的一侧,如果一副图像占有全部可能的灰度级并且分布均匀,则这样的图像有高对比度和多变的灰度色调。直方图均衡化这种方法通常用来增加图像的局部对比度。所以这种方法对于图像前景和背景都太亮或者太暗的情况非常有用,使目标区域从背景脱离出来。
直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。
3、直方图绘制流程
(1)计算图像各灰度像素数目
for rv in img:#遍历图像
for cv in rv:
prob[cv] += 1#算出现次数
(2)计算各灰度出现的概率
h, w = img.shape#图像大小
prob = prob / (h * w)#算概率
(3)计算各灰度出现的概率
prob = np.cumsum(prob) # 计算累计概率
img_map = [int(255 * prob[i]+0.5) for i in range(256)] #像素值 映射的新图
直方图均衡化绘制流程图
(4)图像映射
r, c = img.shape
for ri in range®:
for ci in range©:
img[ri, ci] = img_map[img[ri, ci]]
return img
4、直方图均衡化前后结果对比分析
以清明节放假班级登记表为例原图如下:
三、直方图规定化
直方图规定化,也叫做直方图匹配,用于将图像变换为某一特定的灰度分布,也就是其目的的灰度直方图是已知的。这其实和均衡化很类似,均衡化后的灰度直方图也是已知的,是一个均匀分布的直方图;而规定化后的直方图可以随意的指定,也就是在执行规定化操作时,首先要知道变换后的灰度直方图,这样才能确定变换函数。规定化操作能够有目的的增强某个灰度区间,相比于,均衡化操作,规定化多了一个输入,但是其变换后的结果也更灵活。
1、直方图匹配的实现
直方图规定化的实现可以分为一下四步:
1)计算原图像的累积直方图
2)计算规定直方图的累积直方图
3)计算两累积直方图的差值的绝对值
4)根据累积直方图差值建立灰度级的映射
2、GML和SML原理
GML规定化(组映射)
先列出图像灰度值i,j,计算原始直方图各个灰度值概率Pr(i),规定直方图各个灰度值概率Pz(j),计算原始累计直方图P(i)和规定累计直方图P(j),然后按照P(j)到P(i)寻找最接近的值存储为j,当满足给定的值多于一个时,按惯例取最小值。确定变换关系为i->j,最后列出匹配直方图P(j)。
SML规定化(单映射)
GML规定化中求累积概率过程与SML一致,但在映射关系上与SLM有所区别,GML采用分组映射。且对比时是从目标的累积概率一一与原始图像的累积概率取绝对值最小。
两种方式的具体列子如下图:
图:直方图规定化实列
2、GML和SML实现
(1)SML求累积概率:
def pixel_probability(img):
"""
计算像素值出现概率
"""
assert isinstance(img, np.ndarray)
prob = np.zeros(shape=(256))
for rv in img:#算出现次数
for cv in rv:
prob[cv] += 1
h, w = img.shape
prob = prob/(h * w)#算概率
return prob
prob = pixel_probability(src)
plot(prob, "原图直方图")
prob = np.cumsum ( prob ) #计算原始累计概率
(2)#SML直方图规定化
diff_cdf = [[0 for j in range ( 256 )] for k in range ( 256 )]
# diff_cdf 里是每2个灰度值比率间的差值
for j in range ( 256 ):
for k in range ( 256 ):
diff_cdf[j][k] = abs ( prob[j] - prob1[k] )
lut = [0 for j in range ( 256 )] # 映射表
for j in range ( 256 ):
min = diff_cdf[j][0]
index = 0
for k in range ( 256 ): # 直方图规定化的映射原理
if min > diff_cdf[j][k]:
min = diff_cdf[j][k]#最小差值
index = k#保存下标
lut[j] = ([j, index])
h = int ( img.shape[0] )
w = int ( img.shape[1] )
for j in range ( h ): #对原图像进行灰度值的映射
for k in range ( w ):
img_new1[j, k] = lut[src[j, k]][1]
(4)GML直方图规定化
# 直方图规定化
lut = [0 for j in range ( 256 )] # 映射表
diff_cdf = [[0 for j in range ( 256 )] for k in range ( 256 )]
# diff_cdf 里是每2个灰度值比率间的差值
for j in range ( 256 ):
if prob1[j] != 0:#排除0
for k in range ( 256 ):
diff_cdf[j][k] = abs ( prob[j] - prob1[k] )
if min>diff_cdf[j][k]:
min=diff_cdf[j][k]
flag=k#标记下标
for m in range(flage2,flag):#分组处理
value[m]=j#映射矩阵
min=1
flage2 = flag + 1
lut[j] = ([j, flag])
h = int ( img.shape[0] )
w = int ( img.shape[1] )
for j in range ( h ): # 对原图像进行灰度值的映射
for k in range ( w ):
img_new1[j, k] = lut[src[j, k]][1]