Python, OpenCVでBGRとRGBを変換するcvtColor

Posted: | Tags: Python, OpenCV, 画像処理

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)

bgr opencv imwrite

Pillowで画像処理を行う場合、Image.fromarray()ndarrayPIL.Imageオブジェクトに変換できるが、Pillowでは色の順番はRGB(赤、緑、青)を前提としている。

そのため、OpenCVのimread()で読み込んだ画像のndarrayをそのままPIL.Imageオブジェクトに変換して保存すると、色が誤った画像として保存されてしまう。

pil_img = Image.fromarray(im_cv)
pil_img.save('data/dst/lena_bgr_pillow.jpg')

bgr pillow save

ndarrayPIL.Imageオブジェクトを相互に変換してPillowの関数とOpenCVの関数を両方使いたい場合は、以下に示す方法でBGRとRGBを変換する必要がある。

OpenCVの関数cvtColor()でBGRとRGBを変換

OpenCVの関数cvtColor()を使うとRGBやBGR、HSVなど様々な色空間を相互に変換できる。

dst = cv2.cvtColor(src, code)

引数codeに指定する値については以下のドキュメントを参照。

引数codecv2.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 pillow save

RGB変換後にOpenCVのimwrite()で保存すると、当然、誤った色の画像となる。

cv2.imwrite('data/dst/lena_rgb_cv.jpg', im_rgb)

rgb opencv imwrite

なお、RGBからBGRへ変換する場合は、引数codecv2.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')

前者はファンシーインデックス、後者はスライスを利用している。

関連カテゴリー

関連記事