2013年12月12日木曜日

[OpenCV] PythonのOpenCVで特定の色の画像を判別

複数の画像の中から、特定の色(の多い)の画像のみを抽出する方法を考えてみました。


1.RGB値の平均を求める方法


例えば、このトマトの画像が「赤い」かを判別してみます。



>>> import cv2
>>> img = cv2.imread('tomato.jpg')
>>> averages = img.mean(0).mean(0) # BGRの値を全ピクセルで平均した値
>>> averages
array([ 184.32241784,  194.90715962,  241.32643779])
>>> blue_average, green_average, red_average = averages
>>> if red_average > green_average and red_average > blue_average:
...     print "The image is RED"
... 
The image is RED

img.mean(0).mean(0) では、BGRの値を全ピクセルで平均した値を求めています。

いわゆる赤が BGR = (0, 0, 255) で表されるので、Rの値がBやGよりも大きければ赤い画像です(厳密にはBとGの値が同じくらいで、Rよりも有意に小さい必要がありますが)

この画像では、B,Gの平均値が約190であるのに対してRの平均値が240なので、「赤い」画像であると言って良さそうです。


2.BGRをHSVに変換して、色相から判別する方法


ウェブページなどではいわゆるRGB値(赤青緑)を用いて色を表現しますが、HSV値(色相・彩度・明度)を用いて色を表現する方法があります。

HSV色空間 - Wikipedia

このH(色相)を用いることで、画像が「赤い」かを判別することができそうです。

>>> import cv
>>> import cv2
>>> img_bgr = cv2.imread('tomato.jpg')
>>> img_hsv = cv2.cvtColor(img_bgr, cv.CV_BGR2HSV) # 画像をBGRからHSV色空間に変換
>>> average_hue = img_hsv[:,:,0].mean() # Hの値を全ピクセルで平均した値
>>> average_hue
11.173327464788729

ここで、赤が最も強い(Rの値がB,Gよりも高い)場合、H(色相)は300°〜60°に分布します(OpenCVでは値域が0〜179のため0〜30,150〜179)。よって、色相の平均値がこの値の範囲に収まっていれば、「赤い」画像になります。

ただし、色相を使う場合には注意点が一つあり、真っ白な点や真っ黒な点のように、どの色相にもあてはまる点の色相は0になります。このような点を含めて平均値を求めてしまうと、平均値は必ず0に近い値になってしまいます。このような点を排除するため、S(彩度)の値を使います。

彩度とは読んで字の如く「色の鮮やかさ」のことで、白や黒は0.0、赤・緑・青は1.0(100%, OpenCVでは255)です。よって、この彩度に閾値を設け、彩度が一定の値よりも低い点を排除して平均を求めることで、より正しい色相を求めることが出来ます。

以下が修正版のコードです。

>>> import cv
>>> import cv2
>>> img_bgr = cv2.imread('tomato.jpg')
>>> img_hsv = cv2.cvtColor(img_bgr, cv.CV_BGR2HSV) # 画像をBGRからHSV色空間に変換
>>> valid_hue_list = [[ hsv[0] for hsv in img_line if hsv[1] > 0]
... for img_line in img_hsv] #彩度が0より大きい点のみを採用
>>> average_hue = (sum([sum(line) for line in valid_hue_list]) / 
... float(sum([len(line) for line in valid_hue_list])))
>>> average_hue
21.157771912765661

先程よりも0から遠い、大きな値になりました。純粋な赤色ならばHの平均値は0.0になるはずですが、トマトのヘタは緑色(OpenCVでは色相の値が60.0)なので、その値に引っ張られて約20になったと思われます。


このように色相の平均を求めることで簡易的に色を判別できますが、他にも様々な方法が考えられます。

例えば、色相が赤・緑・青に属するピクセル数を数えて、その大きさが一定値を超えたらその色の画像である、と判断するような方法も考えられます。対象とする画像の特徴と計算時間等を考えることで、より良い方法が見つかるはずです。



0 件のコメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...