OpenCVでは色相の範囲が0~180であることに注意
一般的には色相は0~360の範囲で考えますが、OpenCVでは0~180で考えます。これは、8bitで扱える整数の最大値が255であることに起因するものです。緑色は約120度に当たる色相なので、この付近の色相を持つ画素を見つけ出します。今回は入力画像と同じ大きさの真っ黒な画像をもう1つ用意し、入力画像で緑色だった部分について、相当する位置の画素に255の値を入れていきます。これらの画像は2値画像になります。なお、色相が似ているかどうかを判別するためのIsSimilar関数を作っています。なお、0,360度が赤、60度が黄色、120度が緑、180度がシアン、240度が青、300度がマゼンタを表すおよその色相です。OpenCVでは0~180で色相を表すため、0,180が赤、30が黄色、60が緑、90がシアン、120が青、150がマゼンタを表すおよその色相になります。下の図はOpenCVでの色相と値の対応を示したものです。また、入力画像では緑色の部分の彩度が高いことから、彩度についても一定以上の値となるようなフィルターをかけ、精度の向上を試みています。
各画素に直接アクセスする
dataメソッドでアクセスできます。例えば、HSV画像のimgについて、座標(x,y)の画素のHSVの値を取得するには次のようなコードで表現します。
色相H : img.data[ y * img.step + x * img.elemSize() + 0 ]
彩度S : img.data[ y * img.step + x * img.elemSize() + 1 ]
明度V : img.data[ y * img.step + x * img.elemSize() + 2 ]
今回はHSV画像ですので関係ありませんが、BGR画像の場合には、0で青B、1で緑G、2で赤Rの値が取得できます。なお、img.stepはMatの横幅、img.elemSize()は1つの画素のデータのサイズを表しています。最後に緑色であると判定された画素の数と、全体に占める割合を表示しています。今回は、248518 pixels; 20.1405 %というような結果が得られました。下の画像は緑色であると判定された部分が白で表された2値画像です。
#include "opencv/cv.h"
#include "opencv/highgui.h"
#include <iostream>
using namespace cv;
using namespace std;
bool IsSimilar(int ref, int target, int thr){
if(abs(ref-target)<thr)return 1;
else if(abs(ref-target+180)<thr||abs(ref-target-180)<thr)return 1;
else return 0;
}
int main(){
Mat img = imread("newyork.jpg", IMREAD_UNCHANGED);
Mat hsv_img;
cvtColor(img, hsv_img, CV_BGR2HSV);
Mat green_img=Mat(Size(img.cols,img.rows),CV_8U);
Mat yellow_img=Mat(Size(img.cols,img.rows),CV_8U);
int green_pixels=0;
for(int y = 0; y < hsv_img.rows; ++y){
for(int x = 0; x < hsv_img.cols; ++x){
//OpenCVでは色相Hの範囲が0~180になっていることに注意
//緑は120度 OpenCVでは 120/2=60 あたり
if(
hsv_img.data[ y * hsv_img.step + x * hsv_img.elemSize() + 1 ]>100 &&
IsSimilar(hsv_img.data[ y * hsv_img.step + x * hsv_img.elemSize() + 0 ], 60, 20)
)
{
green_img.data[y * green_img.step + x * green_img.elemSize()]=255;
green_pixels++;
}
}
}
imshow("IMAGE",img);
imshow("green-area",green_img);
cout<<green_pixels<<" pixels; "<<(double)green_pixels/img.cols/img.rows*100<<" %"<<endl;
waitKey(0);
return 0;
}