Python cv2 imwrite() - RGB or BGR

55 views Asked by At

It is confusing how opencv works in python. I understand that cv2.imread() assumes that the image is in BGR. However, when i convert the image from BGR to RGB using cv2.cvtColor(image, cv2.COLOR_BGR2RGB), and the try to save the image and then read it using PIL, the colors are inverted.

Context: I am building a ROS pipeline where I have to use opencv ROS bridge to get images as rostopics and then transform the images using PIL.

Please refer to the following code and output image:

import numpy as np
from matplotlib import pyplot as plt
from PIL import Image as im

image1 = cv2.imread('/home/ali/Pictures/rgb.png' )
image2 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)
cv2.imwrite('/home/ali/Pictures/test_img_bgr_cv.png', image2)
image3 = im.open('/home/ali/Pictures/test_img_bgr_cv.png')

plt.figure(figsize=(10, 10))
plt.subplot(1, 3, 1), plt.imshow(image1)
plt.title('Image 1'), plt.xticks(\[\]), plt.yticks(\[\])

plt.subplot(1, 3, 2), plt.imshow(image2)
plt.title('Image 2'), plt.xticks(\[\]), plt.yticks(\[\])

plt.subplot(1,3,3), plt.imshow(image3)
plt.title('Image 3'), plt.xticks(\[\]), plt.yticks(\[\])

plt.show()

output image

1

There are 1 answers

2
Hushm On

Actually there seems to be a misconception about cv2.imread(), cv2 reads the image in BGR format Yes, but when prompted to save the image or showing it using cv2.imshow it correctly renders them, the problem is in matplotlib partially. Because cv2 uses BGR color format and matplotlib uses RGB color format.

So what are essentially doing is :

  1. Load an image in BGR
  2. Convert the image into RGB
  3. Save it as RGB.
  4. Load it again as BGR
  5. Viewing it inverted with matplotlib.

A better solution would be to remove image3 as below :

from matplotlib import pyplot as plt
import cv2

image1 = cv2.imread('rgb.png')
image2 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)
cv2.imwrite('test_img_bgr_cv.png', image2)


plt.figure(figsize=(10, 10))
plt.subplot(1, 3, 1) 
plt.imshow(image1)
plt.title('Image 1')

plt.figure(figsize=(10, 10))
plt.subplot(1, 3, 2)
plt.imshow(image2)
plt.title('Image 1')

plt.show()

EDIT:

Regarding cv2.imwrite then use Image.open() although I believe it would add necessary complications, you can use the following :

import cv2
from PIL import Image 

image1 = cv2.imread('rgb.png')
image2 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)
cv2.imwrite('test_img_bgr_cv.png', image2)

im = Image.open('test_img_bgr_cv.png') # Load the Image normally
b, g, r = im.split()                   # Split the color channel, change to b, g, r, a in case of need for Alpha.
im = Image.merge("RGB", (r, g, b))     # Reorder the color channels the way intended.

# .show() is for "testing" only
im.show()

The other one is more simple just flip the return of the cv2.imread() :

import cv2
from PIL import Image 

image = cv2.imread('rgb.png')[:, :, ::-1] # The slicing here is done to avoid the height and width of image just reorder them.
img = Image.fromarray(image)
img.show()

P.S.: Please be more accurate regarding what you are asking about.