plant-raspberrypi3のブログ

ラズベリーパイ3とPythonに挑戦して、植物を愛でたり画像を加工したりします。最近はscikit-imageの勉強してます。

OpenCV-Pythonでツバキのお花部分だけ取り出してみた

こんにちは。らずべりーです。
Markdown記法について調べたので、早速使ってみています。 これ便利ですね!

参考にさせていただいたまとめページ。感謝!

igcn.hateblo.jp

ochataro.hatenablog.com

では、そろそろ本題に、、、

植物の画像加工にチャレンジ(やっと)

OpenCV-Pythonに慣れるため、花の部分を取り出してみる画像加工にチャレンジしてみます!
練習しただけなので、この加工した画像を何かに使う予定はないのです。

参考にしたページを以下に貼っておきます。

OpenCV-Pythonチュートリアル — OpenCV-Python Tutorials 1 documentation

使用する素材

今回使う画像はこれ!

f:id:plant-raspberrypi3:20171015123628j:plain

今回は冬に職場で見かけて撮影していたツバキの絞り品種(何かは不明)。綺麗ですねー。
でも、単色のツバキより画像加工の難易度が高そう。。。

撮影はiPhoneで普通にぱしゃり。

実行環境

あとはNumpyとかMatplotlibとか。

作業概要

  1. 画像の読みこみと表示
  2. ぼかし処理
  3. グレースケール画像とHueのみ画像に変換
  4. 2値化
  5. マスク処理

実際の手順

0. 作業簡便化のためのpyプログラム作成

OpenCV-Pythonのプログラムは癖があって書きづらかったため Pythonっぽい文法に置き換えるプログラムopencv_wrap.pyを作りました。

import cv2
import matplotlib.pyplot as plt

def display_bgr_image(img):
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    plt.imshow(img_rgb)

def bgr2hsv(img):
    return cv2.cvtColor(img, cv2.COLOR_BGR2HSV)    

def bgr2gray(img):
    return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

def display_gray_image(img):
    plt.imshow(img)
    plt.gray()
    plt.show()

1. 画像の読みこみと表示

先ほど作ったファイルをcwモジュールとしてインポートしています。

%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
import opencv_wrap as cw

img001_bgr = cv2.imread("IMG_3232.JPG")

cw.display_bgr_image(img001_bgr)

f:id:plant-raspberrypi3:20171015123628j:plain


2. ぼかし処理

ぼかし処理はcv2.blur関数で行います。 ぼかし処理の程度を変えるときは(20,20)を好きな値に変更します。

blur001_bgr = cv2.blur(img001_bgr,(20,20))

cw.display_bgr_image(blur001_bgr)

f:id:plant-raspberrypi3:20171015125837j:plain

余計なコードが入っていたので修正しました[2017/10/21]


3. グレースケール画像とHueのみ画像に変換

2値化のための準備です。

blur001_gray = cw.bgr2gray(blur001_bgr)
blur001_hsv = cw.bgr2hsv(blur001_bgr)
h,s,v = cv2.split(blur001_hsv)

cw.display_gray_image(blur001_gray)
cw.display_gray_image(h)

f:id:plant-raspberrypi3:20171015130219j:plain
グレースケール画像

f:id:plant-raspberrypi3:20171015130250j:plain
Hueのみ画像


4. 2値化

グレースケール画像からは明るい部分(>150)のみを取り出します。
Hue画像からは赤っぽいところ(>120)のみを取り出します。

OpenCVではHueは0-180で色相を表されています。
色見本はこちらのページがわかりやすいです。

d.hatena.ne.jp

2値化処理にはOpenCVは使わず、単純に論理式でTrue or Falseの行列を生成しています。以下のscikit-imageのページを参考にしました。今回、scikit-imageそのものは使わなかったのですが。 *1

3.3. Scikit-image: 画像処理 — Scipy lecture notes

最後に2つの結果を足し合わせて、np.uint8型に変換し、マスク画像としました。 255を掛けているのは結果の確認のためです。

binary_gray = blur001_gray >= 150
binary_h = h >= 120

cw.display_gray_image(255*binary_gray)
cw.display_gray_image(255*binary_h)

binary_sum_raw = binary_gray|binary_h
binary_sum = np.uint8(255*binary_sum_raw)

cw.display_gray_image(binary_sum)

f:id:plant-raspberrypi3:20171015132410j:plain
グレースケール画像を2値化した

f:id:plant-raspberrypi3:20171015132421j:plain
Hueのみ画像を2値化した

f:id:plant-raspberrypi3:20171015132429j:plain
2つの2値化画像を合算した


5. マスク処理

いよいよマスク処理です! cv2.bitwise_and関数でやりました。

img_masked = cv2.bitwise_and(img001_bgr, img001_bgr, mask=binary_sum)

cw.display_bgr_image(img_masked)

f:id:plant-raspberrypi3:20171015132708j:plain

できました!!やったー(^ ^)ノ



さいごに

実際は色々試行錯誤して迷走しまくりましたが、うまくいったものだけを記録してます。 ぐちゃぐちゃでお見せできたものではないので(^ ^;)

難しかった点は、

  • ピンクと白の部分の明るさが違うところ
  • 雄しべの部分だけ色味が全然違うところ

の2点ですね。

背景のごちゃごちゃしているところが除ききれていないですが、そのあたりは今後の課題です。(今回は力尽きた、、、)

おしまい

*1:scikit-imageも使おうかと思ったものの、なんとなく処理スピードがOpenCVよりゆっくりな気がしたので、今回はお蔵入りしました。