本日はOpenCVを使って、特定の範囲の色を抽出してみたいと思います。
例としては(0,0,100)~(100,100,255)のように、色の範囲を与えてやり、それを基に範囲内の画素のみを抽出してみたいと思います。
色の抽出として、「(1) 普通に画像のRGB値を使う」手もありますが、RGBをHSVに変換し、「(2) HSVから色抽出する」例と今回は両方作成して比較してみたいと思います。
目次
HSV : Hue, Saturation, Value
HSVとは、色相(Hue)、彩度(Saturation)、明度(Value)の三つの成分からなる色の表現法のことで、RGBのような光の3原色(赤・緑・青)とは違う3軸で色を表現します。
① 色相(H):色の種類(例えば赤、青、黄色)
② 彩度(S):色の鮮やかさ。
③ 明度(V):色の明るさ。
HSV色空間は人間が色を知覚する方法と類似しているとされているため、例えば照明条件が変わっても色相にはあまり変化が及ばないなど、色の抽出がしやすくなるケースもあります。
今回は、RGBでの抽出と、RGBをHSVに変換してからの抽出の2つのコードを書きましたので掲載します。
参考サイト:HSV色空間(Wikipedia)
今回の環境
・OS : Windows10(64bit)
・Visual Studio 2015 Community(導入済)
・OpenCV 2.4.11(環境構築済とする)
実装コード
(1) RGBによる色抽出
先に実装コードを掲載します。
今回はinRange関数を利用しました。
inRange関数は、最小値のスカラーと最大値のスカラーを定義したときに、その間に収まる画素のマスクを作ってくれます。今回はコード中のs_minからs_maxまでの範囲の画素が取り出されます。
そして、inRange関数としては出力として、マスク画像を得ます。
今回は「赤が100~255、緑が0~100、青が0~100」のマスク画像を抽出したところ、以下のようになりました(上:原画像/下:マスク画像)。
注意点として、OpenCVではRGBではなく、BGRの順でカラーが設定されていますので、「Scalar(B_MIN, G_MIN, R_MIN);」としました。
このマスク画像の白の部分だけを抽出することで、RGB値による色の抽出を行うことができます。今回はcopyTo関数を用いて、入力画像の中でマスクが画像が白の部分だけを抽出して、表示を行いました。
赤の値が大きいところを抽出する形にしたのですが、実際に赤い部分が抜けていることがわかると思います。
(2) HSVによる色抽出
次に、HSVでの色抽出についても書いてみたいと思います。
RGBをHSVに変換する手順が必要なこと以外は特に大きな変更はありません。コードは以下となります。
違いとしては、「cvtColor(input_image_rgb, hsv_image, CV_BGR2HSV, 3);」で変換が必要となることくらいでしょうか。
HSV画像を、普通に表示すると以下のようになります。
BがH値、GがS値、RがV値になっています。よって、暗いところほど赤くなったりしているのがわかると思います。
このHSV値に対してフィルタを掛けますが、注意点があります。
① 色相(H):0~180 (×2すると度数になり、0~360度を示す)
② 彩度(S):0~255
③ 明度(V):0~255
OpenCVでは値が次のように決まっています。彩度と明度が0~255は感覚的に理解しやすいですが、色相(H)は0~180となる点には注意が必要です。この値をオーバーした場合、255までは循環するので0~255の値を使う分には問題ないですが、この認識がないと狙った色を抜くことができません。
色相は
参考サイト:HSV色空間(Wikipedia)
にもあるように、赤(0)からスタートして一回転して赤に戻ります。
今回のサンプルコードでは、赤っぽいところを抜きたかったのでHを160~180にしてみました。結果は以下となります。
一概に比較できるものではありませんが、HSVでも狙った色抽出ができていることがわかると思います。
RGBによる抽出と、状況によって使い分けたりしたいところですね。