【图像处理】——图像的灰度化处理(Python实现三种方法——最大值法、平均值法、加权均值法、gamma校正)
目录
一、什么是图像的灰度化?
二、灰度化的几种方法(最大值法、平均值法、加权均值法、gamma校正)
1、直接调用函数:cv2.cvtColor() 图像颜色空间转换
2、最大值法
(1)概念
(2)代码
(3)结果
3、平均值法
(1)概念
(2)“RuntimeWarning: overflow encountered in ubyte_scalars”问题的解决
(3)代码
(4)结果
4、加权均值法
(1)概念
(2)代码
(3)结果
5、gamma校正
(1)概念
(2)代码
(3)结果
三、不同方法之间的比较
四、疑问:怎么利用Python创建一个空的初始化图像?(np.unit8的应用)
1、关键代码
2、图像展示
3、得到灰度图像矩阵对比
4、利用opencv创建图像参考代码(彩色和灰色均有)
一、什么是图像的灰度化?
众所周知,在数字图像中,任何一张图片的颜色都可以通过RGB三原色进行调节与表现。对于彩色图像而言,其RGB三个通道的数值通常并不一致。所谓的灰度化处理其实就是将彩色图像转换为黑白图像的过程。经过该处理后得到的灰度图像中各个像素点处的RGB三通道数值均相等。
彩色图像由红、绿、蓝三个分量构成,
这些分量分别呈现红、绿、蓝等不同颜色。
而将这些分量调至相同的过程即称为"grayization"
在grayization过程中,
当像素的gray value较高时该点显得明亮
其中最大值255对应白色
而当pixel value最低时则显得较暗
相应的则显得较暗
最小值0对应黑色。
这一过程即被称为grayization
具体可见:《百度百科》
通过将图像进行灰度化处理有助于下一步骤中对图像特征进行提取,并且能够获得该图像的灰度曲线图。
二、灰度化的几种方法(最大值法、平均值法、加权均值法、gamma校正)

这里以上述经典图片为例进行灰度化处理
1、直接调用函数:cv2.cvtColor() 图像颜色空间转换
img2 = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) #灰度化:彩色图像转为灰度图像
img3 = cv2.cvtColor(img,cv2.COLOR_GRAY2RGB) #彩色化:灰度图像转为彩色图像
# cv2.COLOR_X2Y,其中X,Y = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS
AI助手
OpenCV包含一个功能模块能够实现彩色图像转为灰度图像。该功能模块通过颜色空间转换技术生成灰度化的结果图像。
import cv2
def gray_cvt(inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_cvt_image = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)#灰度化
cv2.namedWindow(windowname) # 这行没啥用 控制显示图片窗口的名字
cv2.imshow(windowname, gray_cvt_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_cvt_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
inputimagepath="colorful_lena.jpg"
windowname='gray_cvt'
outimagepath="gray_cvt.jpg"
gray_cvt(inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
AI助手
返回的是一个(200,200)的图像,是一个二维数组,这里的元素值就是B=G=R值


直接调用函数cv2.cvt
2、最大值法
(1)概念
灰度化后的R,G,B得值等于转化前3个值中最大的一个,即:
R=G=B=max(R,G,B)
(2)代码
import cv2
def gray_max_rgb(inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)#读取图像,返回的是一个装有每一个像素点的bgr值的三维矩阵
gray_max_rgb_image = img.copy()#复制图像,用于后面保存灰度化后的图像bgr值矩阵
img_shape = img.shape#返回一位数组(高,宽,3)获得原始图像的长宽以及颜色通道数,一般彩色的颜色通道为3,黑白为1
for i in range(img_shape[0]):#按行读取图片的像素bgr
for j in range(img_shape[1]):#对每一行按照列进行每一个像素格子进行读取
gray_max_rgb_image[i,j] = max(img[i,j][0],img[i,j][1],img[i,j][2])#求灰度值
print(gray_max_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_max_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_max_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
inputimagepath = "colorful_lena.jpg"
windowname = "gray_max_rgb"
outimagepath = "gray_max_rgb.jpg"
gray_max_rgb(inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
AI助手
(3)结果
是一个三维矩阵的返回结果,在其第三维上具有特殊性:三个元素相同,并且满足R、B、G相等。
print(gray_max_rgb_image)#取最后一维的第一组数据作为参考
AI助手


最大值法
3、平均值法
(1)概念
灰度化后R,G,B的值为转化前R,G,B的平均值。即:
R=G=B=(R+G+B)/3
(2)“RuntimeWarning: overflow encountered in ubyte_scalars ”问题的解决
在该过程(增减运算)完成后可能会表现出_溢出现象_:若原始像素值取值范围为0至255之间,则当增减运算导致其数值低于0或高于255时就会产生溢出错误;这种情况下虽然会生成相应的处理图像(尽管这一处理可能导致图像质量下降)。

A runtime warning for overflow was issued for the ubyte_scalars data type. The mean RGB value at position [i, j] is calculated by averaging the red, green, and blue components of img[i, j].

实现该方法就是在操作之前对像素进行强制取整就可完成。
gray_mean_rgb_image[i,j] = (int(img[i,j][0])+int(img[i,j][1])+int(img[i,j][2]))/3
AI助手
(3)代码
#平均值法进行图像灰度化
import cv2
def gray_mean_rgb(inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_mean_rgb_image = img.copy()
img_shape = img.shape
for i in range(img_shape[0]):
for j in range(img_shape[1]):
gray_mean_rgb_image[i,j] = (int(img[i,j][0])+int(img[i,j][1])+int(img[i,j][2]))/3
print(gray_mean_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_mean_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_mean_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
inputimagepath = "colorful_lena.jpg"
windowname = "gray_mean_rgb"
outimagepath = "gray_mean_rgb.jpg"
gray_mean_rgb(inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
AI助手
(4)结果
print(gray_mean_rgb_image)#取最后一维的第一组数据作为参考
AI助手


平均值法
4、加权均值法
(1)概念
灰度化后按照一定权值,对R,G,B的值加权平均,即:


其中红、绿、蓝通道分别赋予了不同权重的数值参数R, G, B。考虑到人眼对绿光最为敏感而对蓝光最为不敏感这一生理特性,在图像处理中通常会赋予绿色通道更高的权重以更好地模拟人眼感知的特点。通过这种方式能够使生成的灰度图像在视觉效果上更加贴近人类观察结果

将得到较易识别的灰度图像。一般时,

得到的灰度图像效果最好
注:一般权重有两套值供选择
Gray= 0.072169B+ 0.715160G+ 0.212671R
Gray= 0.11B+ 0.59G+ 0.3R
AI助手
前一种基于OpenCV开放库采用了灰度权值,而后一种则是一种从人体生理学角度提出的权值(其中人眼对绿色最为敏感,而对蓝色最为不敏感)
说明
(2)代码
#加权均值法进行图像灰度化
import cv2
def gray_weightmean_rgb(wr,wg,wb,inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_weightmean_rgb_image = img.copy()
img_shape = img.shape
for i in range(img_shape[0]):
for j in range(img_shape[1]):
gray_weightmean_rgb_image[i,j] = (int(wr*img[i,j][2])+int(wg*img[i,j][1])+int(wb*img[i,j][0]))/3
print(gray_weightmean_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_weightmean_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_weightmean_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
wr = 0.299
wg = 0.587
wb = 0.114
inputimagepath = "colorful_lena.jpg"
windowname = "gray_weightmean_rgb"
outimagepath = "gray_weightmean_rgb.jpg"
gray_weightmean_rgb(wr,wg,wb,inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
AI助手
(3)结果
print(gray_weightmean_rgb_image)#取最后一维的第一组数据作为参考
AI助手


加权均值法
5、gamma校正
(1)概念

(2)代码
#gamma校正加权均值进行图像灰度化
import cv2
def gray_gamma_weightmean_rgb(wr,wg,wb,gamma,inputimagepath,windowname,outimagepath):
img = cv2.imread(inputimagepath)
gray_gamma_weightmean_rgb_image = img.copy()
img_shape = img.shape
for i in range(img_shape[0]):
for j in range(img_shape[1]):
fenzi = int((wr*img[i,j][2])**gamma)+int((wg*img[i,j][1])**gamma)+int((wb*img[i,j][0])**gamma)
fenmu = wr**gamma + wg**gamma + wb**gamma
gray_gamma_weightmean_rgb_image[i,j] = int((fenzi/fenmu)**(1/gamma))
print(gray_gamma_weightmean_rgb_image)
cv2.namedWindow(windowname) #控制显示图片窗口的名字
cv2.imshow(windowname, gray_gamma_weightmean_rgb_image)#显示灰度化后的图像
cv2.imwrite(outimagepath, gray_gamma_weightmean_rgb_image) # 保存当前灰度值处理过后的文件
cv2.waitKey()#等待操作
cv2.destroyAllWindows()#关闭显示图像的窗口
def main():
wr = 1
wg = 1.5
wb = 0.6
gamma = 2.2
inputimagepath = "colorful_lena.jpg"
windowname = "gray_gamma_weightmean_rgb"
outimagepath = "gray_gamma_weightmean_rgb.jpg"
gray_gamma_weightmean_rgb(wr,wg,wb,gamma,inputimagepath,windowname,outimagepath)
if __name__ == '__main__':
main()
AI助手
(3)结果
print(gray_gamma_weightmean_rgb_image)#取最后一维的第一组数据作为参考
AI助手


gamma修正法
三、不同方法之间的比较

由上图进行各个灰度化结果比较可以清晰的看出:
通过最大值法进行灰度化处理后的图像整体偏亮,在保留主要视觉特征的同时也导致所保留的图像细节信息有所缺失。通常被应用于对原始图像色调较为暗淡的情况进行处理
2、加权平均值法经灰度化处理后整体亮度偏低,在目标区域与背景区域能够清晰辨识方面存在不足;通常情况下适用于对原始色调较为明亮的图像进行处理
3、直接调用函数进行灰度化颜色依旧偏暗
4、该方法实现灰度化处理效果显著然而该方法所需参数数量过多在计算过程中涉及了幂次运算和平方根操作计算速度较慢尤其在批量处理大量图像时效果欠佳硬件配置要求较高。
与gamma修正法相比,在效果上二者相差不大。但不如gamma修正法精确。然而其计算简便且结果较为理想。
因此一般使用均值法进行图片的灰度处理
四、疑问:怎么利用Python创建一个空的初始化图像?(np.unit8的应用)
《掌握如何借助numpy库生成零矩阵、一矩阵以及基于随机数的矩阵》
在上述灰度化处理过程中,生成的图像均为三维数组,并且这些数组中的每个元素都是相同的三个数值。实际上,在这种情况下,二维空间中的完整表示足以完整地表示灰色图像的所有信息——即只需存储单个数值即可完成表示工作。这时候可以通过numpy预先生成一个适当大小的空间,并将其作为基础进行后续操作——然后将预计算好的灰度值赋值到该空间中即可。需要注意的是,在使用numpy进行图像处理时,必须确保生成的空间数据类型为无符号8位整数(uint8),因为这决定了后续显示或操作时是否能够正确呈现图像。
gray_max_rgb_image = np.zeros((img_shape[0], img_shape[1]), np.uint8)
AI助手
这里以最大值法为例:
1、关键代码
# gray_max_rgb_image = img.copy()#复制图像,用于后面保存灰度化后的图像bgr值矩阵
img_shape = img.shape#返回一位数组(高,宽,3)获得原始图像的长宽以及颜色通道数,一般彩色的颜色通道为3,黑白为1
gray_max_rgb_image = np.zeros((img_shape[0], img_shape[1]), np.uint8)#创建一个与原始图像大小一致的图像,初始值为0,即为黑色
cv2.imshow('',gray_max_rgb_image)#这里得到的是一个与原始图像一样大小的黑色初始图像
for i in range(img_shape[0]):#按行读取图片的像素bgr
for j in range(img_shape[1]):#对每一行按照列进行每一个像素格子进行读取
gray_max_rgb_image[i,j] = max(img[i,j][0],img[i,j][1],img[i,j][2])#求灰度值
cv2.imshow('',gray_max_rgb_image)#这里得到的是灰度化后的图像
AI助手
2、图像展示
创建的图像:

创建的图像
灰度化后的图像:

最大值法
3、得到灰度图像矩阵对比
基于原始图像矩阵形状实现灰度化处理后的图像矩阵其最后一个维度的三个数值保持一致即其RGB值完全相同

基于生成的数组完成图像灰度化处理,并构建了一个形状为(200,200)的图像矩阵;在此过程中仅获取单个灰度层次信息。

4、利用opencv创建图像参考代码(彩色和灰色均有)
import cv2 as cv
import numpy as np
def creat_image():
'''
#创建RGB图像
image = np.zeros([400,400,3],np.uint8) #初始图片黑色
#修改第一个通道的值
image[:,:,0] = np.ones([400,400])*255 #输出蓝色的图 第一通道是blue
# 修改第二个通道的值
image[:, :, 1] = np.ones([400, 400])
cv.imshow("new_image",image)
'''
#创建单通道图像 灰度图像
image = np.zeros([400, 400,1], np.uint8)
image[:,:,0] = np.ones([400,400])*127
cv.imshow("new_image", image)
import cv2 as cv
t1 = cv.getTickCount() #获取时间
creat_image()
t2 = cv.getTickCount()
time = (t2-t1)/cv.getTickCount()
print("time:%s ms"%(time*1000)) #花了多长时间 mS
cv.waitKey(0)
#释放窗口
cv.destroyAllWindows()
AI助手
