Opencv(二): 灰度化
Opencv中的灰度化
文章目录
思维导图

前言
在机器视觉和图像处理领域,灰度化是从彩色图像到单通道图像的关键一步,广泛用于车道线检测、人脸识别、图像分割等场景。
一、灰度图基础
要理解灰度化,首先得明确“灰度图”与“彩色图”的核心差异:
- 彩色图:由红(R)、绿(G)、蓝(B)三个通道组成,每个像素需存储3个数值(范围0-255),通过三通道不同比例混合呈现丰富色彩;
- 灰度图:仅含1个通道,每个像素只需1个数值(范围0-255),数值越小越接近黑色,越大越接近白色,最终呈现从黑到白的渐变灰度效果。
简单来说,灰度化的本质是将彩色图的R、G、B三通道信息,通过特定算法合并为单通道灰度值,既保留图像的亮度和轮廓特征,又大幅减少后续处理的计算量。
二、三种灰度化方法
彩色图转灰度图的核心是“如何合并R、G、B三通道”,行业内主流有三种方法,各有适用场景,以下结合同一像素(R=91、G=121、B=46)的计算实例展开说明。
1. 最大值法
原理
从每个像素的R、G、B三个通道值中,直接选取最大的数值作为该像素的灰度值。
核心逻辑:保留通道中最亮的信息,让灰度图整体偏亮,适用于对亮度敏感但无需精准还原的场景。
计算实例
已知像素(R=91,G=121,B=46),三通道最大值为121,因此灰度值=121。
优缺点
- 优点:计算速度最快,无需复杂运算,代码实现简单;
- 缺点:丢失大量通道信息(如本例中R和B通道值被完全忽略),易导致图像细节模糊,仅适合快速预览或简单场景。
2. 平均值法
原理
将每个像素的R、G、B三通道值相加求和,再除以3(通道数),取结果(需整数化)作为灰度值。
核心逻辑:均衡保留三通道信息,让灰度图亮度与原彩色图整体一致,适合对亮度均衡性要求不高的场景。
计算实例
已知像素(R=91,G=121,B=46):
灰度值 =(91 + 121 + 46)÷ 3 = 258 ÷ 3 = 86(结果取整)。
优缺点
- 优点:计算简单,能兼顾三通道信息,灰度效果比最大值法更自然;
- 缺点:未考虑人眼对不同颜色的敏感度(人眼对绿色更敏感,对蓝色最不敏感),可能导致灰度图与视觉感知存在偏差。
3. 加权均值法
原理
根据人眼对R、G、B三通道的敏感度差异,给每个通道分配固定权重,通过“权重×通道值”的乘积求和,得到灰度值。
行业通用权重(经大量视觉实验验证):
- R通道:0.299(人眼对红色敏感度较低);
- G通道:0.587(人眼对绿色敏感度最高);
- B通道:0.114(人眼对蓝色敏感度最低)。
核心逻辑:模拟人眼视觉特性,让灰度图的亮度的主观感受与原彩色图最接近,是工业场景(如车道线检测、医疗影像)的首选方法。
优缺点
- 优点:灰度效果最贴合人眼感知,保留图像细节最完整,是绝大多数专业场景的默认选择;
- 缺点:计算量略高于前两种方法,但在现代计算机和嵌入式设备中,该运算开销可忽略不计。
三种方法核心参数对比
| 方法 | 权重分配 | 计算复杂度 | 灰度效果 | 适用场景 |
|---|---|---|---|---|
| 最大值法 | 取R、G、B中最大值 | 低 | 整体偏亮,细节少 | 快速预览、简单图像标注 |
| 平均值法 | R=1/3,G=1/3,B=1/3 | 中 | 亮度均衡,偏主观 | 非专业场景、教学演示 |
| 加权均值法 | R=0.299,G=0.587,B=0.114 | 中 | 贴合人眼,细节全 | 车道线检测、医疗影像、人脸识别 |
三、三核心方法的代码实现
1.最大值法
import cv2
import numpy as np
#1. 使用cv2.imread()去读取一张彩色图
image_np = cv2.imread('./flower.png')
#2.获取数组的形状
image_shape = image_np.shape
#3.创造一个跟彩色图宽和高相同的单通道图像
image_gray = np.zeros((image_shape[0],image_shape[1]),dtype=np.uint8)
#4.遍历彩色图像中所有的像素点,并去除像素点的三个通道中值最大的那个
for i in range(image_shape[0]):
for j in range(image_shape[1]):
image_gray[i][j] = max(image_np[i,j][0],image_np[i,j][1],image_np[i,j][2])
#5.显示图像
cv2.imshow('image_np',image_np)
cv2.imshow('image_gray',image_gray)
cv2.waitKey(0)
2. 平均值法
# 使用平均法去会复发一张彩色图
import cv2
import numpy as np
#使用opencv的imread函数去读取要灰度化的图片
image_np = cv2.imread('./flower.png')
#2.获取彩色图的形状,方便后续简历灰度图的图片
# shape获取到的顺序是 高和宽
image_shape = image_np.shape
#3.创建灰度图模板,方便后续去接收彩色图所计算的灰度结果
#np.zeros也是按照高和宽的顺序去创建图像
image_gray = np.zeros((image_shape[0],image_shape[1]),dtype=np.uint8)
#4.遍历彩色图中的每个像素点,使用平均值的方法去计算每个像素点的灰度值
#使用嵌套的for循环去遍历彩色图的所有像素点
for i in range(image_shape[0]):
for j in range(image_shape[1]):
#在循环中,获取彩色图中的每个像素点的平均值,并将其赋值给灰度模板图的对应位置
image_gray[i][j] = (int(image_np[i,j][0])+int(image_np[i,j][1])+int(image_np[i,j][2])) // 3
#5.显示图像
cv2.imshow('image_np',image_np)
cv2.imshow('image_gray',image_gray)
cv2.waitKey(0)
3.加权平均法
#如何去使用opencv去读取一张图片
# opencv 用 BGR 的顺序存储
import cv2
import numpy as np
#使用opencv去读取一张图片,在opencv中使用cv2.imread去读取一张图片
#cv2.imread():两个参数,第一个是要读取的图片的位置及名称(名称要包括文件的后缀名)
#第二个参数是指定读取进来的图片的格式,默认使用BGR彩色图的格式,如果有特殊需要可以去opencv官网查看
image_np = cv2.imread('flower.png')#返回一个数组
# print(type(image_np))
#使用opencv的接口去灰度化一张图像
cv_gray = cv2.cvtColor(image_np,cv2.COLOR_BGR2GRAY)
#shape:是Ndarray的一个属性,用来查看数组的形状
#shape读取到的形状与图像实际宽和高是相反的,shape[0]代表的是图像的高度
#shape[1]代表的是图像的宽度
image_shape = image_np.shape
#创建一个单通道的全0数组,此时需要创建一个与原图大小相同的单通道数组
#zeros:按照高和宽的顺序来创建的
#image_gray就是我们创建的一个灰度图模板,像素值全是0
image_gray = np.zeros((image_shape[0],image_shape[1]),dtype = np.uint8)
# 定义权重
# weight_red = 0.299
# weight_green = 0.587
# weight_blue = 0.114
#把每一个点的三通道值乘以权重在加和
#遍历彩色图像,对彩色图像中每个像素点都进行加权平均的操作
#求出每个像素点的灰度值,然后将得到的灰度值赋值给image_gray
#通过嵌套循环,让我们能遍历到图片中的所有像素点
# for i in range(image_shape[0]):
# for j in range(image_shape[1]):
# #遍历到所有像素点之后开始进行加权平均的计算
# image_gray[i][j] = round(image_np[i,j][0] * weight_blue + image_np[i,j][1] * weight_green + image_np[i,j][2] * weight_red)
#显示彩色图
cv2.imshow('image_np',image_np)
#使用cv2.imshow()去显示一下image_gray
cv2.imshow('cv_gary',cv_gray)
#使用cv2.waitKey(0)将图像固定下来
cv2.waitKey(0)
注意:三种方法的输出结果和下面展示的输出结果一致就不展示了
四、灰度化实验现象
import cv2
import numpy as np
if __name__ == "__main__":
path = "./flower.png"
image_np = cv2.imread(path)
img_shape = image_np.shape
image_np_gray = np.zeros((img_shape[0], img_shape[1]), dtype=np.uint8) # image_np.copy()
# 加权灰度化
wr = 0.299
wg = 0.587
wb = 0.114
for i in range(img_shape[0]):
for j in range(img_shape[1]):
image_np_gray[i, j] = (int(wr * image_np[i, j][2]) + int(wg * image_np[i, j][1]) + int(
wb * image_np[i, j][0]))
cv2.imshow("image_np_gray", image_np_gray)
cv2.waitKey(0)
输出结果为:注意:修改图片,只需要导入你的图片路径即可
注意:如果觉得图片太大,可以使用resize函数调整图片大小
五、总结
三种方法的使用情况
- 快速预览、简单标注场景:选最大值法(速度最快,无需复杂运算);
- 教学演示、非专业场景:选平均值法(逻辑直观,均衡保留三通道信息);
- 工业检测、专业场景(如车道线检测、医疗影像):必选加权均值法(贴合人眼感知,细节保留最完整,是行业默认标准)。
更多推荐



所有评论(0)