64

I have the following piece of code:

imgs = glob.glob('/home/chipin/heart/tray.png')
current_img = io.imread(imgs[0])
cv2.imwrite('/home/chipin/heart/01.png', current_img[0:511,0:511])  

The size of picture is 512*512, after being saved, a blue picture turns yellow. It seems that a channel is abandoned. I really don't know why.

Here is the value of current_img:

value of current_img

Dan Mašek
  • 17,852
  • 6
  • 57
  • 85
StalkerMuse
  • 1,001
  • 3
  • 11
  • 22
  • I assume the `io.imread` is the one from skimage? – Dan Mašek Feb 23 '17 at 03:23
  • 6
    If so, then the issue is in the fact that [`skimage.io.imread`](http://scikit-image.org/docs/dev/api/skimage.io.html#skimage.io.imread) loads image as RGB, but numpy assumes the image to be [BGR](http://docs.opencv.org/trunk/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce). This means that blue and red planes get flipped. Why don't you just use `cv2.imread` to load the image instead? – Dan Mašek Feb 23 '17 at 03:25
  • thanks I suppose so.And how can I correct it please? – StalkerMuse Feb 23 '17 at 03:30
  • 2
    Either use `cv2.imread`, which will read in BGR format as well (this is the default for OpenCV), or use `cv2.cvtColor` to convert from RGB to BGR. – Dan Mašek Feb 23 '17 at 03:37
  • Oh, and the last channel full of zeros -- looks like transparency. In that case it's RGBA <-> BGRA. – Dan Mašek Feb 23 '17 at 04:04
  • thank you sooo much – StalkerMuse Feb 23 '17 at 04:40
  • No problem :) Remember, documentation is your friend ;) | BTW, on StackOverflow, it's customary to upvote answers you find helpful (that's the little upwards pointing triangle next to the answer). Also, if it's an answer to your question and you deem it the best one, there's a little checkmark that let's you "accept" it. – Dan Mašek Feb 23 '17 at 04:45

2 Answers2

143

Your problem is in the fact that skimage.io.imread loads image as RGB (or RGBA), but OpenCV assumes the image to be BGR or BGRA (BGR is the default OpenCV colour format). This means that blue and red planes get flipped.


3 Channel Images

Let's try this out with the following simple test image:

Input image


First let's try your original algorithm:

import skimage.io
import cv2

img = skimage.io.imread('sample.png')
cv2.imwrite('sample_out_1.png', img)

We get the following result:

Result 1

As you can see, red and blue channels are visibly swapped.


The first approach, assuming you want to still use skimage to read and cv2 to write is to use cv2.cvtColor to convert from RGB to BGR.

Since the new OpenCV docs don't mention Python syntax, in this case you can also use the appropriate reference for 2.4.x.

import skimage.io
import cv2

img = skimage.io.imread('sample.png')
cv2.imwrite('sample_out_2.png', cv2.cvtColor(img, cv2.COLOR_RGB2BGR))    

Now we get the following output:

Result 2


An alternative is to just use OpenCV -- use cv2.imread to load the image. In this case we're working only with BGR images.

NB: Not providing any flags means cv2.IMREAD_COLOR is used by default -- i.e. image is always loaded as a 3-channel image (dropping any potential alpha channels).

import cv2

img = cv2.imread('sample.png')
cv2.imwrite('sample_out_3.png', img)

Result 3


4 Channel Images

From your screenshot, it appears that you have a 4 channel image. This would mean RGBA in skimage, and BGRA in OpenCV. The principles would be similar.

  • Either use colour conversion code cv2.COLOR_RGBA2BGRA
  • Or use cv2.imread with flag cv2.IMREAD_UNCHANGED
Dan Mašek
  • 17,852
  • 6
  • 57
  • 85
2

The image on input (as a png) is in RGB order but the image in memory (as a cv::Mat) is in BGR order. Use cv2.imread() for input. So, imread() will internally convert from rgb to bgr and imwrite() will do the opposite, all under the hood.

Here's how you do it:

current_img = cv2.imread('/home/chipin/heart/tray.png')
cv2.imwrite('/home/chipin/heart/01.png', current_img)  
Abu Noman Md Sakib
  • 322
  • 2
  • 5
  • 20