GIS奮闘記

現役GISエンジニアの技術紹介ブログ。主にPythonを使用。

スポンサーリンク

Python と OpenCV で画像処理をしてみよう!

さて、本日は OpenCV を使って画像処理をしてみようと思います。私は最近画像を扱うことが多く、OpenCV を使ってもう少し画像関連の知識の幅を広げようと思っています。

今回のテーマは GIS とは直接は関係ないのですが、GIS の世界では航空写真など多くの画像を扱います。GIS のお仕事に興味がある方は画像の扱いにも慣れておくことをおすすめします。

画像関連のエントリーをいくつか書いていますので、興味のある方はぜひ読んでみてください。

www.gis-py.com

www.gis-py.com

www.gis-py.com

OpenCV とは?

オープンソースのコンピュータビジョン向けのライブラリですね。要するに画像や動画用のライブラリですね。OpenCV は元々 C/C++ で使えるライブラリでしたが、Python でも動作するようになりました。ありがたい話です。

今回試すこと

まずは以下の基本的な機能を試してみたいと思います。

  1. 画像を読み込む
  2. 興味領域(ROI)の抽出
  3. 画像のブレンド
  4. 画像の重ね合わせ
  5. 画像から顔と目を検出

実行環境

Windows 10 64bit
Python 3.6.6

使用する画像

大田区公式PRキャラクターの「はねぴょん」の画像を使用します。

f:id:sanvarie:20210111155935p:plain

サンプルコード

画像を読み込む
# -*- coding: utf-8 -*-
import cv2

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg", 1) # カラーで読込
    cv2.imshow("test", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このようにはねぴょんの画像が読み込まれたことが確認できました。

f:id:sanvarie:20210111160141p:plain

興味領域(ROI)の抽出

ROIとは、Region of Interestの略で、処理対象とする領域のことですね。以下を ROI としてみます。「ペイント」アプリを使えば ROI とする座標がわかります。

f:id:sanvarie:20210111162318p:plain

# -*- coding: utf-8 -*-
import cv2

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg", 1) # カラーで読込
    roi = img[68:128, 35:143] # ROI領域
    cv2.imwrite(r"D:\blog\data\opencv\hane_roi.jpg", roi) # 保存

if __name__ == '__main__':
    main()

このように ROI を抽出することができました。 f:id:sanvarie:20210111163959p:plain

画像のブレンド

以下の画像をはねぴょんの画像にブレンディングします(はねぴょんの画像の重みを0.7、上の画像の重みを0.3に設定)。

f:id:sanvarie:20210111171544p:plain

# -*- coding: utf-8 -*-
import cv2

def main():
    img1 = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
    img2 = cv2.imread(r"D:\blog\data\opencv\opencv_logo.png")

    # 画像の大きさをあわせる
    img1 =cv2.resize(img1,(200,200))
    img2 =cv2.resize(img2,(200,200))

    img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
    img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

    blended = cv2.addWeighted(src1=img1,alpha=0.7,src2=img2,beta=0.3,gamma=0)

    cv2.imshow("blended",blended)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように画像がブレンドされたことがわかります。

f:id:sanvarie:20210111171929p:plain

画像の重ね合わせ

今度はブレンドではなく、画像を重ね合わせてみようと思います。

# -*- coding: utf-8 -*-
import cv2

def main():
    img1 = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
    img2 = cv2.imread(r"D:\blog\data\opencv\opencv_logo.png")

    # 片方の画像を小さくする
    img2 =cv2.resize(img2,(100,100))

    #img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
    #img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

    large_img = img1
    small_img = img2

    large_img[0:small_img.shape[0], 0:small_img.shape[1]] = small_img

    cv2.imshow("large_img", large_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように画像が重なったことがわかります。 f:id:sanvarie:20210111172544p:plain

画像から顔と目を検出

OpenCV では顔,目,笑顔などを検出することができます(検出させるものを学習させることも可能です)。今回は顔と目を検出してみようと思いますが、はねぴょんでは検出ができないので以下の画像を使用します。

f:id:sanvarie:20210111173628j:plain

# -*- coding: utf-8 -*-
import os
import cv2

# OpenCVのディレクトリ
opencv_path = r"C:\Python\Lib\site-packages\cv2\data"

def main():

    # 顔検出用データ
    face_cascade = cv2.CascadeClassifier(os.path.join(opencv_path,
                                         "haarcascade_frontalface_default.xml"))

    # 目検出用データ
    eye_cascade = cv2.CascadeClassifier(os.path.join(opencv_path,
                                        "haarcascade_eye.xml"))

    # 画像読込
    img = cv2.imread(r"D:\blog\data\opencv\CR7.jpg")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 顔検出
    faces = face_cascade.detectMultiScale(gray,
                                          scaleFactor=1.3,
                                          minNeighbors = 5,
                                          minSize=(30, 30))
    for (x,y,w,h) in faces:
        # 顔検出した部分に枠を描画
        img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
        roi_gray = gray[y:y+h, x:x+w]
        roi_color = img[y:y+h, x:x+w]

        # 目検出
        eyes = eye_cascade.detectMultiScale(roi_gray)
        for (ex,ey,ew,eh) in eyes:
            # 目検出した部分に枠を描画
            cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

    cv2.imshow("img", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように顔と目を検出することができることがわかります。 f:id:sanvarie:20210111181036p:plain

さいごに

まだまだ OpenCV の基本機能を触れただけですが、簡単なコードで画像から顔と目を検出できたり非常に便利なライブラリということがわかりました。OpenCV はすごく多機能なライブラリのため、次回以降でもOpenCV の紹介をしていこうと思います。本日は以上です。