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.

The easiest way to convert is to use openCV cvtColor.

``````import cv2
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))
``````

Edit:

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 `:,:` while `::-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
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 `ImageMath` module.

### Edit:

Joe’s solution is even better, I was overthinking it. 🙂

TLDR: Use `cv2.cvtColor(img, cv2.COLOR_BGR2RGB))` if you already import `cv2`.

Speed comparison:

``````%%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 `img` in `numpy` array format.

But, `cv2.imread()` is most likely the reason you got BGR image. Not `Image.open()`.

If you have an alpha band, use this:

``````img = img[:,:, [2, 1, 0, 3]]
``````