如何将RGB图像(3通道)转换为灰度图像(1通道)并保存?

5

我正在处理一个深度学习项目,有很多图片,但这些图片不需要彩色。我使用以下方式保存了它们:

import matplotlib.pyplot as plt

plt.imsave('image.png', image, format='png', cmap='gray')

然而,当我检查图像的形状时,结果是:
import cv2
img_rgb = cv2.imread('image.png')
print(img_rgb.shape)
(196,256,3)

即使我观看的图像是灰度的,但我仍然有3个颜色通道。我意识到我需要进行一些代数运算,以将这些3个通道转换为1个单独的通道。

我尝试了线程 "如何在Python中将RGB图像转换为灰度图像?" 中描述的方法,但我感到困惑。

例如,当使用以下方法进行转换时:

from skimage import color
from skimage import io
img_gray = color.rgb2gray(io.imread('image.png'))
plt.imsave('image_gray.png', img_gray, format='png')

然而,当我加载新图像并检查其形状时:
img_gr = cv2.imread('image_gray.png')
print(img_gr.shape)
(196,256,3)

我在那个帖子上尝试了其他方法,但结果都是一样的。我的目标是获得形状为(196,256,1)的图像,这将使卷积神经网络的计算强度大大降低。

任何帮助都将不胜感激。


我有完全相同的问题。你找到任何解决方法了吗?我使用了matplotlib和手动方法,但两者都导致3通道灰度图像 :| - Shilan
4个回答

5
您的第一个代码块:
import matplotlib.pyplot as plt
plt.imsave('image.png', image, format='png', cmap='gray')

这是将图像保存为RGB格式,因为在向imsave提供RGB数据时忽略了(请参见pyplot文档)。

您可以通过取三个波段的平均值将数据转换为灰度,可以使用color.rgb2gray,也可以使用numpy:

import numpy as np
from matplotlib import pyplot as plt
import cv2

img_rgb = np.random.rand(196,256,3)
print('RGB image shape:', img_rgb.shape)

img_gray = np.mean(img_rgb, axis=2)
print('Grayscale image shape:', img_gray.shape)

输出:

RGB image shape: (196, 256, 3)
Grayscale image shape: (196, 256)

img_gray 现在已经是正确的形状,但是如果你使用 plt.imsave 来保存它,它仍然会写入三个通道,每个像素的 R == G == B。这是因为,我相信,PNG 文件需要三个(或四个)通道。警告:我不确定这一点:我希望能够得到纠正。

plt.imsave('image_gray.png', img_gray, format='png')
new_img = cv2.imread('image_gray.png')
print('Loaded image shape:', new_img.shape)

输出:

Loaded image shape: (196, 256, 3)

避免此问题的一种方法是将图像保存为numpy文件,或者将一批图像保存为numpy文件:

np.save('np_image.npy', img_gray)
new_np = np.load('np_image.npy')
print('new_np shape:', new_np.shape)

输出:

new_np shape: (196, 256)

另一件事情是您可以保存灰度PNG(使用imsave),但只读取第一个波段:
finalimg = cv2.imread('image_gray.png',0)
print('finalimg image shape:', finalimg.shape)

输出:

finalimg image shape: (196, 256)

PNG不需要三个波段。RBGA非常常见,灰度或带阿尔法通道的灰度也是可能的。 - Håken Lid
@HåkenLid,能否给个例子,如何将一个波段保存为PNG格式。 - jmsinusa
1
官方的PNG规范支持此功能。https://www.w3.org/TR/2003/REC-PNG-20031110/“支持索引色、灰度和真彩色图像,以及可选的Alpha通道。样本深度范围从1到16位不等。”但是完全有可能存在不完全支持PNG标准所有部分的图形库。 - Håken Lid
谢谢,这非常有用!我认为一个好的行动方案是: 1-按原样加载图像(3个颜色通道) 2-加载数据并将其转换为1个颜色通道 3-将其保存为numpy文件 4-将其馈送到神经网络中我能预见到的唯一问题是,我认为期望的输入将是(196,256,1),而我将拥有的是(196,256)。它们是否相等? - J. Devez
2
你可以在输入上使用numpy.expand_dims(array, 2)来添加额外期望的维度。 - jmsinusa

3
正如事实所证明的那样,我正在使用的深度学习库Keras在其图像预处理步骤中有自己的将图像转换为单色通道(灰度)的方法。
当使用ImageDataGenerator类时,flow_from_directory方法需要color_mode参数。将color_mode =“grayscale”设置为自动将PNG转换为单个颜色通道!

https://keras.io/preprocessing/image/#imagedatagenerator-methods

希望这能在未来帮助到某人。

问题是我没有从磁盘读取!我正在从相机获取图像,并且我希望立即将其转换为灰度,而无需将其保存在磁盘上! - Shilan

0

尝试使用这种方法

import imageio
new_data = imageio.imread("file_path", as_gray =True)
imageio.imsave("file_path", new_data)

代码第2行的可选参数"as_gray = True"执行实际的转换。

0
如果你想要添加额外的通道,使其与灰度图像具有相同的值,可能是为了使用需要3个通道输入形状的特定模型。
假设你的图片是28 x 28,所以你的形状是(28, 28, 1)。 def add_extra_channels_to_pic(pic):
if pic.shape == (28 , 28 , 1):
    pic = pic.reshape(28,28)
    pic =  np.array([pic , pic , pic])
    # to make the channel axis in the end
    pic = np.moveaxis(pic , 0 , -1) 
    return pic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接