思维导图

在这里插入图片描述

前言

在机器视觉和图像处理领域,灰度化是从彩色图像到单通道图像的关键一步,广泛用于车道线检测、人脸识别、图像分割等场景。

一、灰度图基础

要理解灰度化,首先得明确“灰度图”与“彩色图”的核心差异:

  • 彩色图:由红(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函数调整图片大小

五、总结

三种方法的使用情况

  • 快速预览、简单标注场景:选最大值法(速度最快,无需复杂运算);
  • 教学演示、非专业场景:选平均值法(逻辑直观,均衡保留三通道信息);
  • 工业检测、专业场景(如车道线检测、医疗影像):必选加权均值法(贴合人眼感知,细节保留最完整,是行业默认标准)。
Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐