緑色のピクセルを数える

ニューヨークの衛星画像から領域内の緑色の部分を検出することで、緑地面積を計算します。今回は単純な明るさによる2値化のみでなく、色座標の変換などの内容を含みます。また、各画素に直接的にアクセスする方法のサンプルにもなっています。

次のような衛星写真を用意しました。この画像から緑色の部分の面積を求めます。
newyork

画像処理に関する疑問にお答えできます。お気軽にお問い合わせください。


13 件のコメント

    • コメントありがとうございます。

      色相は一般的には0~360ですが、OpenCVではint型が0~255までの整数しか保持できないために、色相を一般的な値に1/2を掛けて保持しています。すなわち、一般的には120が緑ですが、OpenCVでは60が緑になります。

      さて、次の行でも180を足し引きして判定している部分ですが、まず、abs(ref-target)<thr の部分はそのままで、2つの色相の差がthr以下であればtrueを返すという意味になります。次の行ですが、今回は緑(60)を見つけたいため、targetが60になっていますので、実は不要になります。しかし、例えば、赤(0=180)を見つけたいときには色相環は環状になっていますので、10も170もどちらも赤に近いということになります。このときに先の一行だけだと、targetに0を指定した時に10だけが赤に近いと判定されてしまい、170についてはabs(170-10)=160ですので赤に近くないと判定されてしまいます。これを解消するために180足し引きして、もう一度判定しています。このように色相環において、値が近いか否かを示すためには0と180が一周回って同じ色相であることを考慮する必要があります。

    • 早速回答してくださり本当にありがとうございます。とても丁寧ですぐに理解することができましたm(_ _)m
      こちらは、お時間あるときでいいんですが、よろしければ、こちらについてもご教授願います。。 if(
      hsv_img.data[ y * hsv_img.step + x * hsv_img.elemSize() + 1 ]>100 &&

      このif文の判定は緑であるならば、その画素の彩度は100より大きいだろう。と言う理解で大丈夫でしょうか。

    • よかったです。hsv_img .data[ y * hsv_img.step + x * hsv_img.elemSize() + 1 ]>100としているのは、彩度sを取り出しているのですが、いくら色相が緑60に近くても彩度が小さければ灰色に近くなり緑っぽくはならないためです。そのため今回は彩度を100以上にしています。

    • なるほど、とてもわかりやすいです!ありがとうございます。

      今回は明度については検討してないですが、色の判定には不要なのでしょうか?

    • どこまでやるかの問題になりますが、今回は若草色も深緑色も緑として取りたかったので明度では条件をつけていません。もちろんあまりに薄い緑や濃い緑を除外するなら明度でも条件をつけるのがベターだと思われます。

    • 本当にありがとうございました。とても助かりました。

      これからも利用させていただきますm(_ _)m

  • コメント失礼します。
    IsSimilar(hsv_img.data[ y * hsv_img.step + x * hsv_img.elemSize() + 0 ], 60, 20)
    の文章の最後の20の値は、何を示しているのか教えてください。プログラミング初心者で初歩的な質問になるかもしれませんが何卒よろしくお願いします。

    • bool IsSimilar(int ref, int target, int thr)
      部分を見てもらうといいのですが、色相の差がいくつ以下であれば似た色と判定するかという引数です。

    • 回答ありがとうございます!理解することができました。
      黒色の割合を算出する場合では、明度を0に設定して、色相と彩度については条件をつけなくてもいいのですか?

    • そうなります。ただ、真っ黒なピクセルということでしたら、HSVに変換しなくても、(R,G,B)=(0,0,0)という判定方法でもよいと思います。

  • コメントを残す