Python, OpenCVでBGRとRGBを変換するcvtColor
OpenCVの関数imread()
で画像ファイルを読み込むと色の順番がBGR(青、緑、赤)になる。一方、Pillowでは色の順番はRGB(赤、緑、青)を前提としている。
そのため、Pillowの関数とOpenCVの関数を両方使いたい場合はBGRとRGBを変換する必要がある。
OpenCVの関数cvtColor()
を使う方法と、単純にndarray
の順番を入れ替える方法がある。
ここでは、以下の内容について説明する。
- OpenCVはBGR、PillowはRGB
- OpenCVの関数
cvtColor()
でBGRとRGBを変換 cvtColor()
を使わずにBGRとRGBを変換
OpenCVはBGR、PillowはRGB
カラー画像を読み込む場合、OpenCVのimread()
では行(高さ) x 列(幅) x 色(3)
のNumPy配列ndarray
として読み込まれる。色の順番はBGR(青、緑、赤)。
画像を保存するOpenCVの関数imwrite()
はBGRの順番を前提としているので、そのまま使うと正しい画像として保存される。
import cv2
import numpy as np
from PIL import Image
im_cv = cv2.imread('data/src/lena.jpg')
cv2.imwrite('data/dst/lena_bgr_cv.jpg', im_cv)
Pillowで画像処理を行う場合、Image.fromarray()
でndarray
をPIL.Image
オブジェクトに変換できるが、Pillowでは色の順番はRGB(赤、緑、青)を前提としている。
そのため、OpenCVのimread()
で読み込んだ画像のndarray
をそのままPIL.Image
オブジェクトに変換して保存すると、色が誤った画像として保存されてしまう。
pil_img = Image.fromarray(im_cv)
pil_img.save('data/dst/lena_bgr_pillow.jpg')
ndarray
とPIL.Image
オブジェクトを相互に変換してPillowの関数とOpenCVの関数を両方使いたい場合は、以下に示す方法でBGRとRGBを変換する必要がある。
OpenCVの関数cvtColor()でBGRとRGBを変換
OpenCVの関数cvtColor()
を使うとRGBやBGR、HSVなど様々な色空間を相互に変換できる。
dst = cv2.cvtColor(src, code)
引数code
に指定する値については以下のドキュメントを参照。
引数code
をcv2.COLOR_BGR2RGB
とすると、その名前の通りBGRからRGBへの変換となる。
RGBに変換すると、PIL.Image
オブジェクトに変換し保存しても正しい画像として保存される。
im_rgb = cv2.cvtColor(im_cv, cv2.COLOR_BGR2RGB)
Image.fromarray(im_rgb).save('data/dst/lena_rgb_pillow.jpg')
RGB変換後にOpenCVのimwrite()
で保存すると、当然、誤った色の画像となる。
cv2.imwrite('data/dst/lena_rgb_cv.jpg', im_rgb)
なお、RGBからBGRへ変換する場合は、引数code
をcv2.COLOR_RGB2BGR
とする。PIL.Image
オブジェクトで読み込んでndarray
に変換後、OpenCVのimwrite()
で保存する場合はこちらを使う。
im_pillow = np.array(Image.open('data/src/lena.jpg'))
im_bgr = cv2.cvtColor(im_pillow, cv2.COLOR_RGB2BGR)
cv2.imwrite('data/dst/lena_bgr_cv_2.jpg', im_bgr)
cvtColor()
はカラー画像をグレースケールに変換するのにも利用できる。
cvtColor()を使わずにBGRとRGBを変換
BGRとRGBを変換するだけであればcvtColor()
を使わなくても、NumPyの基本機能で実現できる。
方法はいくつかあるが、例えば以下のようにできる。2通り。
im_bgr = cv2.imread('data/src/lena.jpg')
im_rgb = im_bgr[:, :, [2, 1, 0]]
Image.fromarray(im_rgb).save('data/dst/lena_swap.jpg')
im_rgb = im_bgr[:, :, ::-1]
Image.fromarray(im_rgb).save('data/dst/lena_swap_2.jpg')
前者はファンシーインデックス、後者はスライスを利用している。