ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Python 中将 RGB 图像转换为灰度图像?

我正在尝试使用 matplotlib 读取 RGB 图像并将其转换为灰度。

在matlab中我使用这个:

img = rgb2gray(imread('image.png'));

matplotlib tutorial 他们没有涵盖它。他们只是在图像中阅读

import matplotlib.image as mpimg
img = mpimg.imread('image.png')

然后他们对数组进行切片,但这与根据我的理解将 RGB 转换为灰度不同。

lum_img = img[:,:,0]

我很难相信 numpy 或 matplotlib 没有将 rgb 转换为灰色的内置函数。这不是图像处理中的常见操作吗?

我编写了一个非常简单的函数,可以在 5 分钟内处理使用 imread 导入的图像。这是非常低效的,但这就是为什么我希望内置一个专业的实现。

Sebastian 改进了我的功能,但我仍然希望找到内置的功能。

matlab的(NTSC/PAL)实现:

import numpy as np

def rgb2gray(rgb):

    r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

    return gray
请注意,您可以编写与 rgb2gray 函数相同的内容:gray = np.mean(rgb, -1)。如果它实际上是 rgba,可能会出现 rgb[...,:3]
嗯,gray = np.mean(rgb, -1) 工作正常。谢谢。有什么理由不使用它吗?为什么我要使用以下答案中的解决方案?
grayscale wikipedia page表示RGB转灰度的方法不唯一,但给出了一个常用的基于亮度的公式。它与 np.mean(rgb, -1) 完全不同。
所以我想我想要Matlab's version0.2989 * R + 0.5870 * G + 0.1140 * B 我假设这是执行此操作的标准方式。
不应该是 0.2990 * R + 0.5870 * G + 0.1140 * B 吗?权重总和应等于 1 而不是 0.9999。在这里检查:en.wikipedia.org/wiki/Grayscale

s
smcs

Pillow 做这件事怎么样:

from PIL import Image
img = Image.open('image.png').convert('L')
img.save('greyscale.png')

如果输入图像中存在 alpha(透明度)通道并且应该保留,请使用模式 LA

img = Image.open('image.png').convert('LA')

使用 matplotlib 和 the formula

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

你可以这样做:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])

img = mpimg.imread('image.png')     
gray = rgb2gray(img)    
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()

如果他必须使用 matplotlib 出于其他原因,他应该能够使用内置的 colorsys.rgb_to_yiq() 进行变换加上一个切片来获取亮度通道。
为什么.convert('LA')?为什么不.convert('gray')?似乎不必要的神秘。 PIL documentation 没有提及转换函数的“LA”。
使用 PIL: cannot write mode LA as JPEG,我需要使用 L 模式而不是 LA
img = Image.open('image.png').convert('LA') 必须是 img = Image.open('image.png').convert('L')
@BluePython:LA 模式具有亮度(亮度)和 alpha。如果您使用 LA 模式,则 greyscale.png 将是保留 image.png 的 Alpha 通道的 RGBA 图像。如果您使用 L 模式,则 greyscale.png 将是 RGB 图像(没有 alpha)。
y
yangjie

您还可以使用 scikit-image,它提供了一些函数来转换 ndarray 中的图像,例如 rgb2gray

from skimage import color
from skimage import io

img = color.rgb2gray(io.imread('image.png'))

注:此转换中使用的权重针对当代 CRT 荧光粉进行了校准:Y = 0.2125 R + 0.7154 G + 0.0721 B

或者,您可以通过以下方式读取灰度图像:

from skimage import io
img = io.imread('image.png', as_gray=True)

我得到 0
知道我的目标是使用 GLCM 功能(greycoprops)
io.imread 的注意事项:“as_grey”已被弃用,取而代之的是“as_gray”。用法相同,只是美国化的拼写。 :)
我相信这是对手头问题最有用的答案,它的输出也与 matplotlib 和 numpy 兼容。
我正在使用颜色对象,但我的图像现在有点偏红,而不是灰色(黑色和白色)。我需要将 cmap 用作 gray' then only the image is shown as gray in pyplot.imshow()` 吗?有什么想法吗 ?我哪里错了?
M
Maximilian Peters

在 Ubuntu 16.04 LTS(带 SSD 的 Xeon E5 2670)上使用 Python 3.5 运行 1000 个 RGBA PNG 图像(224 x 256 像素)对三个建议方法的速度进行了测试。

平均运行时间

pil : 1.037 秒

scipy: 1.040 秒

sk : 2.120 秒

PIL 和 SciPy 给出了相同的 numpy 数组(范围从 0 到 255)。 SkImage 给出从 0 到 1 的数组。此外,颜色转换略有不同,请参阅 CUB-200 dataset. 中的示例

https://i.stack.imgur.com/ZLd5vm.png

https://i.stack.imgur.com/eQ4KIm.png

https://i.stack.imgur.com/DTjVSm.png

https://i.stack.imgur.com/43cy1m.png

https://i.stack.imgur.com/f5fy9m.png

代码

性能 run_times = dict(sk=list(), pil=list(), scipy=list()) for t in range(100): start_time = time.time() for i in range(1000): z = random。选择(filenames_png) img = skimage.color.rgb2gray(skimage.io.imread(z)) run_times['sk'].append(time.time() - start_time) start_time = time.time() for i in range( 1000): z = random.choice(filenames_png) img = np.array(Image.open(z).convert('L')) run_times['pil'].append(time.time() - start_time) start_time = time.time() for i in range(1000): z = random.choice(filenames_png) img = scipy.ndimage.imread(z, mode='L') run_times['scipy'].append(time.time( ) - start_time) for k, v in run_times.items(): print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v))) 输出 z = ' Cardinal_0007_3025810472.jpg' img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255 IPython.display.display(PIL.Image.fromarray(img1).convert('RGB')) img2 = np.array (Image.open(z).convert('L')) IPython.display.display(PIL.Image.fromarray(img2)) img3 = scipy.ndimage.imread(z, mode='L ') IPython.display.display(PIL.Image.fromarray(img3)) 比较 img_diff = np.ndarray(shape=img1.shape, dtype='float32') img_diff.fill(128) img_diff += (img1 - img3) img_diff -= img_diff.min() img_diff *= (255/img_diff.max()) IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB')) 导入 import skimage.color 导入 skimage。 io import random import time from PIL import Image import numpy as np import scipy.ndimage import IPython.display 版本 skimage.version 0.13.0 scipy.version 0.19.1 np.version 1.13.1


SciPy 的图像 I/O 字面意思是 PIL/Pillow。因此,测试 SciPy 有效地重新测试了 PIL/Pillow,而 SciPy 的包装函数引入的开销可以忽略不计。用 OpenCV(它不利用 PIL/Pillow)代替 SciPy(它利用)会更有用。尽管如此,感谢专门的基准测试! SciKit 造成的明显放缓令人着迷……也令人恐惧。
@CecilCurry 感谢 OpenCV 的创意!等我有空的时候再补充。
点赞!不是我正在寻找的答案,但非常非常有趣:)
D
Diamantatos Paraskevas

您始终可以使用 OpenCV 中的 imread 从一开始就将图像文件读取为灰度:

img = cv2.imread('messi5.jpg', 0)

此外,如果您想将图像读取为 RGB,请进行一些处理,然后转换为灰度,您可以使用 OpenCV 中的 cvtcolor

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

Ftr:0 标志是 cv2.CV_LOAD_IMAGE_GRAYSCALE
Y
YPCrumble

最快和当前的方法是使用通过 pip install Pillow 安装的 Pillow

那么代码是:

from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')

请注意,如果您没有像上例那样链接方法,convert 会返回图像的转换副本
不适用于 32 位 PNG,值将被限制为 255
S
Silas Ray

该教程是作弊的,因为它是从以 RGB 编码的灰度图像开始的,所以他们只是对单个颜色通道进行切片并将其视为灰度。您需要做的基本步骤是从 RGB 颜色空间转换为使用近似亮度/色度模型(例如 YUV/YIQ 或 HSL/HSV)进行编码的颜色空间,然后切掉类似亮度的通道并将其用作你的灰度图像。 matplotlib 似乎没有提供转换为 YUV/YIQ 的机制,但它确实允许您转换为 HSV。

尝试使用 matplotlib.colors.rgb_to_hsv(img),然后从数组中切出最后一个值 (V) 以获得灰度。它与亮度值不太一样,但这意味着您可以在 matplotlib 中完成所有操作。

背景:

http://matplotlib.sourceforge.net/api/colors_api.html

http://en.wikipedia.org/wiki/HSL_and_HSV

或者,您可以使用 PIL 或内置 colorsys.rgb_to_yiq() 转换为具有真实亮度值的色彩空间。您也可以全力以赴并推出自己的 luma-only 转换器,尽管这可能有点过头了。


M
M.Innat

使用 this formula

Y' = 0.299 R + 0.587 G + 0.114 B 

我们可以做的

import imageio
import numpy as np
import matplotlib.pyplot as plt

pic = imageio.imread('(image)')
gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 
gray = gray(pic)  
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))

但是,GIMP 将颜色转换为灰度图像的软件有三种算法来完成这项任务。


x
xemexpress

你可以这样做:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb_to_gray(img):
        grayImage = np.zeros(img.shape)
        R = np.array(img[:, :, 0])
        G = np.array(img[:, :, 1])
        B = np.array(img[:, :, 2])

        R = (R *.299)
        G = (G *.587)
        B = (B *.114)

        Avg = (R+G+B)
        grayImage = img.copy()

        for i in range(3):
           grayImage[:,:,i] = Avg
           
        return grayImage       

image = mpimg.imread("your_image.png")   
grayImage = rgb_to_gray(image)  
plt.imshow(grayImage)
plt.show()

R
Ruaidhrí Primrose

如果您已经在使用 NumPy/SciPy,您可以as well use

scipy.ndimage.imread(file_name, mode='L')


scipy.ndimage.imread()scipy.misc.imread() 在 SciPy 1.0.0 中都是 formally deprecated,将在 SciPy 1.2.0 中永久删除。虽然 SciPy 的文档推荐 imageio.imread() 作为合适的替代品,但这个函数的 API 是赤裸裸的到荒谬的地步。它no支持灰度转换,因此仍然不适合许多应用程序——包括我们的应用程序。 </sigh>
@CecilCurry,如何使用 imageio 将彩色图像转换为灰度?
n
naren

使用 img.Convert(),支持“L”、“RGB”和“CMYK”。模式

import numpy as np
from PIL import Image

img = Image.open("IMG/center_2018_02_03_00_34_32_784.jpg")
img.convert('L')

print np.array(img)

输出:

[[135 123 134 ...,  30   3  14]
 [137 130 137 ...,   9  20  13]
 [170 177 183 ...,  14  10 250]
 ..., 
 [112  99  91 ...,  90  88  80]
 [ 95 103 111 ..., 102  85 103]
 [112  96  86 ..., 182 148 114]]

第 5 行应该是 img = img.convert('L') 吗?
M
Martin Thoma

我通过谷歌来到这个问题,寻找一种将已经加载的图像转换为灰度的方法。

这是使用 SciPy 的一种方法:

import scipy.misc
import scipy.ndimage

# Load an example image
# Use scipy.ndimage.imread(file_name, mode='L') if you have your own
img = scipy.misc.face()

# Convert the image
R = img[:, :, 0]
G = img[:, :, 1]
B = img[:, :, 2]
img_gray = R * 299. / 1000 + G * 587. / 1000 + B * 114. / 1000

# Show the image
scipy.misc.imshow(img_gray)

好的。我只想指出一个较短的解决方案是 img_gray = numpy.average(img, weights=[0.299, 0.587, 0.114], axis=2)
@Akavall 很高兴知道,谢谢!你知道你的捷径是否更快吗?如果没有,我会保留我的,因为它更容易理解。
我没有计时,我的直觉是 numpy.average 有点快,但实际上并没有什么不同。你的解决方案很清楚,并且有关于 R、G、B 的相关信息,所以我会保留它。我的评论更多的是一个额外的选择,而不是替代品。
scipy.ndimage.imread()scipy.misc.imread() 在 SciPy 1.0.0 中都是 formally deprecated,将在 SciPy 1.2.0 中永久删除。您可能只想使用 Pillow 的内置灰度转换支持(ala unutbuanswer),而不是。
你的代码中有哪些神奇的数字? 299、587、114……
S
Shamshirsaz.Navid

使用 OpenCV 很简单:

import cv2

im = cv2.imread("flower.jpg")

# To Grayscale
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imwrite("grayscale.jpg", im)

# To Black & White
im = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite("black-white.jpg", im)

https://i.stack.imgur.com/J4eEv.png


A
Abdul Sadhiq

当所有 3 个颜色通道 (RGB) 中的像素值相同时,该像素将始终为灰度格式。

将 RGB 图像转换为灰度的一种简单直观的方法是获取每个像素中所有颜色通道的平均值并将值分配回该像素。

import numpy as np
from PIL import Image

img=np.array(Image.open('sample.jpg')) #Input - Color image
gray_img=img.copy()

for clr in range(img.shape[2]):
    gray_img[:,:,clr]=img.mean(axis=2) #Take mean of all 3 color channels of each pixel and assign it back to that pixel(in copied image)

#plt.imshow(gray_img) #Result - Grayscale image

https://i.stack.imgur.com/0F6KF.jpg

https://i.stack.imgur.com/Xy0hW.jpg


您可以使用:img = np.mean(color_img, axis=2) 但这样做不是正确的方法,请阅读:e2eml.school/convert_rgb_to_grayscale.html
t
techraf
image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()

您可以直接使用 greyscale() 进行转换。