Each Answer to this Q is separated by one/two green lines.
I have an image where the colors are BGR. How can I transform my PIL image to swap the B and R elements of each pixel in an efficient manner?
I know it’s an old question, but I had the same problem and solved it with:
img = img[:,:,::-1]
Just to add a more up to date answer:
With the new cv2 interface images loaded are now numpy arrays automatically.
But openCV cv2.imread() loads images as BGR while numpy.imread() loads them as RGB.
The easiest way to convert is to use openCV cvtColor.
import cv2 srcBGR = cv2.imread("sample.png") destRGB = cv2.cvtColor(srcBGR, cv2.COLOR_BGR2RGB)
Assuming no alpha band, isn’t it as simple as this?
b, g, r = im.split() im = Image.merge("RGB", (r, g, b))
Hmm… It seems PIL has a few bugs in this regard…
im.split() doesn’t seem to work with recent versions of PIL (1.1.7). It may (?) still work with 1.1.6, though…
Adding a solution using the ellipsis
image = image[...,::-1]
In this case, the ellipsis
... is equivalent to
::-1 inverts the order of the last dimension (channels).
This was my best answer. This does, by the way, work with Alpha too.
from PIL import Image import numpy as np import sys sub = Image.open(sys.argv) 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)
Just a quick footnote for anyone writing code that might have to deal with 4-channel images, and discovering that the simple numpy answer seems to be eating their alpha channel.
np_image[:,:,[0,1,2]] = np_image[:,:,[2,1,0]]
will preserve the alpha data if there is a fourth channel, whereas
np_image = np_image[:,:,[2,1,0]]
will overwrite the 4-channel image with only reversed 3-channel data. (And the even simpler numpy answer, img = img[:,:,::-1], will give you ARGB data, which would be bad, too. 🙂
import cv2 srcBGR = cv2.imread("sample.png") destRGB = cv2.cvtColor(srcBGR,cv2.COLOR_BGR2RGB)
Just to clarify Martin Beckets solution, as I am unable to comment.
You need cv2. in front of the color constant.
im = Image.frombuffer('RGB', (width, height), bgr_buf, 'raw', 'BGR', 0, 0)
Using the ideas explained before… using numpy you could.
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")
Additionally it can remove the Alpha channel.
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
Application of other solutions. Just for a temporary measure.
import numpy im = Image.fromarray(numpy.array(im)[:,:,::-1])
You should be able to do this with the
Joe’s solution is even better, I was overthinking it. 🙂
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) if you already import
%%timeit img_ = Image.fromarray(img[...,::-1]) # 5.77 ms ± 12.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) %%timeit img_ = Image.fromarray(img[...,[2,1,0]]) # 6.2 ms ± 2.43 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) %%timeit img_ = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 442 µs ± 4.84 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Problem is, OP ask if
img is already in
PIL image format, whereas
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) require
numpy array format.
cv2.imread() is most likely the reason you got BGR image. Not
If you have an alpha band, use this:
img = img[:,:, [2, 1, 0, 3]]