PIL 旋转图像颜色(BGR -> RGB)

78

我有一张颜色以BGR编码的图片。如何以高效的方式将每个像素的B和R元素交换,从而转换我的PIL图片?

14个回答

153
我知道这是一个老问题,但我遇到了同样的问题。我使用以下代码解决了它:
img = img[:, :, ::-1]

3
数据有三个维度:宽度、高度和颜色。::-1 有效地颠倒了颜色的顺序。宽度和高度不受影响。 - Peter9192
11
好的,我明白了您的说明并进行了测试。::-1实际上是numpy操作[start:end:step]的简写形式,其中start/end会自动确定。 - Wesley Ranger
4
为了更加清晰明了,img = img[:, :, : :-1] 等同于 img = img[:, :, [2,1,0]]。 我认为后者更好,因为它更加明确。 - EuWern
16
img[:, :, : :-1] 不等同于 img[:, :, [2,1,0]]。前者使用基本索引,后者使用高级索引。后者会复制您的图像,而前者不会。 - Ryan Soklaski
2
这也比上面一个答案中建议的cv2.cvtColor函数表现更出色。 - Vinícius M

112

仅补充最新的答案:

在新的cv2接口中,图像会自动加载为numpy数组。
但是openCV cv2.imread()将图像加载为BGR格式,而numpy.imread()则将其加载为RGB格式。

最简单的转换方式是使用openCV cvtColor。

import cv2
srcBGR = cv2.imread("sample.png")
destRGB = cv2.cvtColor(srcBGR, cv2.COLOR_BGR2RGB)

3
如果你正在使用OpenCV,那么你几乎唯一需要使用BGR图像。你的解决方案是正确的。另一个最佳答案是可行的,但在处理大型图像时会变慢。 - Zach Garner
为什么这个不在顶部? - DollarAkshay
19
因为最简单的解决方案就是:img = img[..., ::-1],意思是将图片进行水平翻转。 - Ryan Soklaski
1
cv2保证图像是连续的吗?OpenCV(至少在C++中)会在4字节边界上开始每一行,因此在移动原始字节时必须小心。 - Martin Beckett
谢谢这个...我正在使用它们在同样的代码中,让我疯狂了一段时间@RyanSoklaski 如果不知道opencv或PIL的默认值,那实际上更加令人困惑,但非常整洁。 - Eliethesaiyan

35

如果没有 alpha 通道,难道不是这么简单吗?

b, g, r = im.split()
im = Image.merge("RGB", (r, g, b))

编辑:

嗯... 看起来PIL在这方面有一些错误... im.split() 在最近版本的PIL(1.1.7)中似乎无法正常工作。不过,它可能仍然适用于1.1.6版本...


解决方案是在第一时间正确加载图像 = P,但这似乎很可爱。 - Claudiu
14
np.roll会将BGR格式转换为RBG格式,而不是RGB格式。如果你想在numpy中进行此操作,可以使用 data[...,[2,1,0]] 来交换通道。但是如果您已经在使用OpenCV或PIL,则建议采用Martin Beckett的解决方案。 - Luke Yeager
另一个numpy替代@LukeYeager的建议:np.flip(image_bgr, axis=2) - hoohoo-b

16

使用省略号添加解决方案

image = image[...,::-1]

在这种情况下,省略号...等同于:,:,而::-1则是倒转最后一维(通道)的顺序。


10

这是我的最佳答案。顺便说一句,这也适用于Alpha。

from PIL import Image
import numpy as np
import sys 

sub = Image.open(sys.argv[1])
sub = sub.convert("RGBA")
data = np.array(sub) 
red, green, blue, alpha = data.T 
data = np.array([blue, green, red, alpha])
data = data.transpose()
sub = Image.fromarray(data)

6

如果您正在编写可能涉及4通道图像的代码,并且发现简单的numpy答案似乎会吞噬它们的alpha通道,请注意以下提示。

np_image[:,:,[0,1,2]] = np_image[:,:,[2,1,0]]

如果存在第四个通道,将保留alpha数据,而

np_image = np_image[:,:,[2,1,0]]

将只有反转的三通道数据的图像覆盖 4 通道图像。(而更简单的 numpy 答案, img = img[:,:,::-1],将给你 ARGB 数据,这也是不好的。 :))

4
import cv2
srcBGR = cv2.imread("sample.png")
destRGB = cv2.cvtColor(srcBGR,cv2.COLOR_BGR2RGB)

为了澄清Martin Beckets的解决方案,因为我无法评论。 在颜色常量前面需要加上cv2。


1
啊,很有用,谢谢。请注意,您可以建议编辑,如果被批准,您将获得+2声望。 - Claudiu
1
谢谢,Claudiu,我会尝试的: “编辑必须至少为6个字符;这篇文章是否还有其他需要改进的地方?” 好吧 - 那并不顺利 ;-) - user2692263

4

其他解决方案的应用。仅作为临时措施。

import numpy

im = Image.fromarray(numpy.array(im)[:,:,::-1])

这通常是我处理图像的方式,不过如果它有alpha层,可以使用以下代码:Image.fromarray(np.array(img)[:,:,:3][:,:,::-1]) - Lewis Morris
1
你可以直接在im变量上应用切片,因为它是一个数组,不需要再次调用numpy。 - Nikolay Frick

3
im = Image.frombuffer('RGB', (width, height), bgr_buf, 'raw', 'BGR', 0, 0)

1
你能详细说明一下吗?因为显然你需要使用np.shape或类似的方法来获取维度信息。另外,bgr_buf是什么? - Muhammad Yasirroni

2
使用之前解释的思路,使用numpy可以...
bgr_image_array = numpy.asarray(bgr_image)
B, G, R = bgr_image_array.T
rgb_image_array = np.array((R, G, B)).T
rgb_image = Image.fromarray(rgb_image_array, mode='RGB')

此外,它可以移除 Alpha 通道。

assert bgra_image_array.shape == (image_height, image_width, 4)
B, G, R, _ = bgra_image_array.T
rgb_image_array = np.array((R, G, B)).T

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