Pythonで自分用のAIを作ろう7-opencvを使ってみる2 | グラ山ギターのブログ

グラ山ギターのブログ

毎週健康のために山登りをしています。低い山ばかりですが播磨の山々は岩山が多く景観がすばらしい所が多いです。山頂などで演奏しています。 井上陽水のカバーが多いです。
暑い時期は山登りは控えています。

前回はPythonでopencvを使ってカメラや動画ファイルから読み込みや動画ファイルへの書き込みについてのプログラムを紹介しました。今回はもう少し高度な画像処理について紹介します。
https://docs.opencv.org/master/db/d27/tutorial_py_table_of_contents_feature2d.html 参照
ここには、色々と画像の特徴抽出と特徴マッチングなどの解説が書いてあります。
特徴点抽出方法には、Harrisコーナーディテクターや、SURF、FAST、BRIEF、ORBなどがありますが、ここでは、PCのカメラから入力した画像からリアルタイムで処理結果を表示するプログラムを紹介します。
 
 まず、古典的なHarris Corner detector(1988)で、輝度勾配から角かエッジかを判定する方法です。
M={{IxIx,Ixiy},{IyIx,IyIy}}として(Ixは輝度のx方向微分、Iyは輝度のy方向微分)、その固有値λ1,λ2を求め
λ1λ2-k(λ1+λ2)が正であればコーナーと判断する方法です。
-----
import numpy as np #Numpyをインポート
import cv2 as cv #opencvをインポート
cap = cv.VideoCapture(0)  #カメラをオープン
while(cap.isOpened()):    #カメラOKなら
    # Capture frame-by-frame
    ret, frame = cap.read()
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) #グレイに変換
    gray = np.float32(gray)  #32bit浮動小数点に変換
    dst = cv.cornerHarris(gray,2,3,0.04) #ブロックサイズ2,微分3x3,k=0.04
    #result is dilated for marking the corners, not important
    dst = cv.dilate(dst,None) #1画素膨張
    # Threshold for an optimal value, it may vary depending on the image.
    frame[dst>0.01*dst.max()]=[0,255,0] #特徴点を緑表示
    cv.imshow('Harris',frame)
    if cv.waitKey(1) & 0xFF == ord('q'): #qキーを押すと終了
        break
cap.release()           #カメラをクローズ
cv.destroyAllWindows()  #ウィンドウ消去
-----
実行すると、Harrisコーナーディテクターで検出された特徴点がウィンドに画像と共に緑色の点で表示される。

このコーナーディテクターは、平行移動や僅かなノイズで大きく左右されて、フレーム毎に特徴点として検出されたり、消えたりするのが良く分かる。ノイズの影響を少なくするため、2つ目の微分パラメータを3→5にして5x5で計算すrと、より安定するが、やはりノイズの影響を受けやすい。また、コントラストが少なかったり、暗い箇所でのコーナーが検出できないという欠点がある。
 
特徴点検出としてさらに改良が加えられ、FASTやBRIEFが提案されましたが、これらは特許権利化されており、opencvにより、両法の特徴を融合したORBが考案されました。
ORBのプログラム例は、
-----
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
cap = cv.VideoCapture(0) #カメラオープン
orb = cv.ORB_create()    #ORBディテクター初期化
while(cap.isOpened()):
    ret, frame = cap.read()  #フレーム画像取り込み
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)  #グレイスケール化
    kp = orb.detect(gray,None)   #ORBで特徴点検出
    kp, des = orb.compute(gray, kp) #特徴点の記述を行う
    # 特徴点を緑色で元のframe画像に書込み、img2に代入
    img2 = cv.drawKeypoints(frame, kp, None, color=(0,255,0), flags=0)
    cv.imshow('ORB',img2)
    if cv.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv.destroyAllWindows()
-----
ORBはHarrisディテクターに比べて、ノイズや移動に対してかなり安定していることが判る。
次にHarr特徴ベースの顔検出デモプログラムを紹介する。
OpenCVにはすでに、顔、目、笑顔などのための事前に訓練された多くの分類子を作成しています。これらのXMLファイルは https://github.com/opencv/opencv/tree/master/data/haarcascades にあります。必要なXMLファイルをjupyterの作業ディレクトリにコピーしておきます。
-----
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#顔および目の学習済みデータをロード
face_cascade = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv.CascadeClassifier('haarcascade_eye.xml')
cap = cv.VideoCapture(0)  #カメラオープン
while(cap.isOpened()):
    ret, frame = cap.read()  #フレーム画像取り込み
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)  #グレイスケール化
    #顔検出
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    for (x,y,w,h) in faces:
        #青色で四角形描画
        cv.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
        roi_gray = gray[y:y+h, x:x+w]  #顔の領域を抜き出す
        roi_color = frame[y:y+h, x:x+w]
        eyes = eye_cascade.detectMultiScale(roi_gray)  #顔の領域から目を検出
        for (ex,ey,ew,eh) in eyes:
            #目の領域を緑の四角形で描画する
            cv.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
    cv.imshow('Face detection',frame)
    if cv.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv.destroyAllWindows()
----

このようにPythonでopencvを利用すれば、簡単なプログラムで複雑な処理がリアルタイムに実行できます。すごいですね!