【Python】OpenCVで扱える主要な色空間

画像には必ず色があり、色を操ることで物体の検知が可能になる場合もあります。

OpenCVでは、色の情報は色空間(color space)として保持されます。色空間はルールを決めて色を並べる形式のことで、座標で色を指定できるという特徴があります。

色空間にはいくつか種類があり、それぞれ色の並びが異なります。

今回は、OpenCVでよく用いられる色空間とその特徴について紹介していきます。

サンプルに用いる画像

Pythonのコードを示す際に、色の違いがわかるように以下のルービックキューブの画像を用います。

LearnOpenCVというサイトから拝借しています。順序だててOpenCVの解説がされているサイトで、非常にわかりやすいです。

英語が多少読める方は参考にしてみてください

https://learnopencv.com/color-spaces-in-opencv-cpp-python/

RGB

RGBは赤 (red) 緑 (green) 青 (blue) の頭文字で、加法混色の色空間です。加法混色とは、赤、緑、青の原色を混ぜ合わせることで様々な色を表現することをいいます。

RGBにおける三原色は光の三原色のことを指します。なので、色を混ぜ合わせるごとに白に近づいていきます。絵具で色を混ぜ合わせる場合と真逆になるので注意してください。

RGB - Wikipedia
RGBのイメージ(Wikipediaより)

Pythonで色を分解してみる

ルービックキューブの画像を赤の要素、青の要素、緑の要素に分解してみます。要素はチャネルとも呼ばれます。

import cv2

img = cv2.imread('input/cube_outdoor.jpg')

#色の分割
img_bgr = cv2.split(img)

cv2.imshow('img_red', img_bgr[0])
cv2.imshow('img_blue', img_bgr[1])
cv2.imshow('img_green', img_bgr[2])

cv2.waitKey(0)
cv2.destroyAllWindows()
明るいルービックキューブをRGBのチャネルで分解した画像
明るいルービックキューブ

RGBによる色の判別は、明度に大きく左右されます。同様の処理を暗いルービックキューブの画像で実行すると以下のようになります。

暗いルービックキューブをRGBのチャネルで分解した画像
暗いルービックキューブ

たとえばblueの画像を見たとき、白と青が明るい画像よりも判別しづらくなっていることがわかります。このように条件によって色の分解にばらつきがでると、実際の色検知の際の悩みの種となります。

つまるところ、RGBには色に関する情報と明るさに関する情報が含まれているのです。

HSV

HSVは色相(Hue)、彩度(Saturation・Chroma)、明度(Value・Brightness)の三つの成分からなる色空間です。

HSVはよく三次元の円錐で表現されます。

HSV色空間の円錐(Wikipediaより)

このとき、色相は円錐の底面(画像では上部)の色環で表されます。また彩度は円錐の中心からの距離、明度は円錐の頂点(画像では下部)からの距離で表されます。

Pythonで色を分解してみる

ルービックキューブの画像をH,S,Vにそれぞれ分解してみます。

import cv2

img = cv2.imread('input/cube_outdoor.jpg')

img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

#色の分割
h, s, v = cv2.split(img)

cv2.imshow('h', h)
cv2.imshow('s', s)
cv2.imshow('v', v)

cv2.waitKey(0)
cv2.destroyAllWindows()
明るいルービックキューブをHSVのチャネルで分解した画像
明るいルービックキューブ

同様に、暗いルービックキューブの画像もHSVに分解して比較してみたいと思います。

暗いルービックキューブをHSVのチャネルで分解した画像
暗いルービックキューブ

H(色相)は、画像の明るさが変わっても大きな違いがないことがわかります。同様に、S(彩度)にも違いは見られません。

V(明度)は暗いルービックキューブの画像で暗くなっていることがわかります。当然ですが(笑)。

HやSの要素を用いれば、明るさによる違いを吸収できそうです。

YCrCb

YCrCbはRGB由来の色空間で、以下の3つの要素を有します。

  • Y:ガンマ補正後のRGBから得られる輝度(または明度)
  • Cr:R(Red)- Y(赤要素と輝度の差)
  • Cb:B(Blue) – Y(青要素と輝度の差)

YCrCbでは、輝度と色度を別のチャネルに分解します。この色空間は高画質アナログ映像信号の伝送などに用いられます。

Pythonで色を分解してみる

ルービックキューブの画像をY, Cr, Cbに分解します。

import cv2

img = cv2.imread('input/cube_outdoor.jpg')

img = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)

#色の分割
Y, Cr, Cb = cv2.split(img)

cv2.imshow('Y', Y)
cv2.imshow('Cr', Cr)
cv2.imshow('Cb', Cb)

cv2.waitKey(0)
cv2.destroyAllWindows()
明るいルービックキューブをYCrCbのチャネルで分解した画像
明るいルービックキューブ

暗いルービックキューブの画像も分解してみます。

暗いルービックキューブをYCrCbのチャネルで分解した画像
暗いルービックキューブ

Yが輝度ということもあり、明るい画像と暗い画像で違いが見られます。Cr,Cbについても、輝度を計算に含んでいるのでそれぞれ微妙に異なっています。ですが、明るさ以外の色の感じは似ているといえます。

OpenCVの学習におすすめ書籍

PythonでOpenCV始めてみようという方におすすめなのが以下書籍です。実装例も豊富なので、1からコードを書かずとも学習を進めることができます。

オライリーの1冊は読み物というより辞書としての利用におすすめです。お値段結構しますが、細かい情報までしっかりと詰め込まれています。

まとめ

OpenCVで扱える主な色空間について解説してきました。

画像解析では白黒画像を用いる場合が多いですが、色による検知を行う場合もあります。その場合、今回紹介した色空間を駆使して特定の色だけ取り出したりといった処理が必要になります。次回は、実際に特定の色部分だけを取り出してみたいと思います。

OpenCVの基礎を身につけるためのロードマップは以下を参考にしてください。

ではでは👋