緑色のピクセルを数える

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での色相と値の対応を示したものです。また、入力画像では緑色の部分の彩度が高いことから、彩度についても一定以上の値となるようなフィルターをかけ、精度の向上を試みています。
hue

各画素に直接アクセスする

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値画像です。
green-area

#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;
}

画像処理でお困りのことはありませんか?


様々なご相談に応じることができます。様々なデータに関して解析の実績がありますので、処理方法について少しだけ相談に乗って欲しいという方も、実装までお願いしたいという方も、お気軽にお問い合わせください!