Python OpenCVを学習してみた 

OpenCV(Open Source Computer Vision Library)は、画像や動画の処理に必要な機能を様々に提供するライブラリです。画像の変換やフィルタ処理や変形、物体判定や物体認識や顔認識、カメラの入出力など豊富な機能があり、とても便利です。

OpenCVで画像の読み込み・変換をしてみる

以前にStable Diffusionの記事で使用した画像を使用します。
「sample.png」として保存しておきましょう。

読み出した画像のデータの高さ・幅・色の情報を表示してみます。

下記の結果の色「3」は [B,G,R]=[0,0,0]~[255,255,255] を意味します。

import cv2

img = cv2.imread("sample.png")
print(img.shape)

赤色だけにしたい場合は、以下のようにすると可能です。

import cv2

img = cv2.imread("sample.png")

# [B,G,R]のB,Gの値をゼロに
img[:, :, (0, 1)] = 0

# ファイルに保存
cv2.imwrite("sample_red.png", img)

from IPython.display import Image,display_png
display_png(Image("sample_red.png"))

グレースケール変換をしてみます。

import cv2

img = cv2.imread("sample.png")
# グレイスケールに変換
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# ファイルに保存
cv2.imwrite("sample_gry.png", gry)

from IPython.display import Image,display_png
display_png(Image("sample_gry.png"))

ソーベルフィルター・Cannyフィルタ(共にエッジ検出)、ネガポジ反転、2値画像・輪郭の描画をしてみます。

import cv2

img = cv2.imread("sample.png")

# ソーベルフィルタを適用
sobel = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=5)
# ファイルに保存
cv2.imwrite("sample_sobel.png", sobel)

# Cannyフィルタを適用
canny = cv2.Canny(img, 30, 200)
# 白黒反転
canny = 255 - canny
# ファイルに保存
cv2.imwrite("sample_canny.png", canny)

# ネガポジ反転
nega = cv2.bitwise_not(img)
# 白黒反転でも同じ結果が得られます。
#nega = 255 - img
# ファイルに保存
cv2.imwrite("sample_nega.png", nega)

# 2値画像の作成
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gry, 100, 255, cv2.THRESH_BINARY)
# ファイルに保存
cv2.imwrite("sample_thresh.png", thresh)

# 2値画像を元に輪郭の描画
# 輪郭の抽出
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cts = cv2.drawContours(img, contours, -1, color=(0,255,0), thickness=2)
# ファイルに保存
cv2.imwrite("sample_contours.png", cts)

from IPython.display import Image,display_png
display_png(Image("sample_sobel.png"))
display_png(Image("sample_canny.png"))
display_png(Image("sample_nega.png"))
display_png(Image("sample_thresh.png"))
display_png(Image("sample_contours.png"))

OpenCVでWebカメラの画像を取り込んでみる

OpenCVを使用すると、簡単にWebカメラの画像を取り込むことが可能です。

import cv2

# カメラのキャプチャを開始
cap = cv2.VideoCapture(0)

while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()

    #フレームが取得できなかった場合は、画面を閉じる
    if not ret:
        break
    
    # ウィンドウに出力
    cv2.imshow("Frame - Press ESC or ENTER to exit.", frame)
    # 10ms間隔で更新する
    key = cv2.waitKey(1)

    # Escキーを入力されたら画面を閉じる
    if key == 27:
        break

    # Enterキーを入力されたら画面を閉じる
    if key == 13:
        break

# 後処理
cap.release()
cv2.destroyAllWindows()

画像が表示されたウインドウでEscキーまたはEnterキーを押すと終了させています。

取得した画像(変数frame)に先ほど紹介した変換処理を加えて、リアルタイムに見ることも可能です。


OpenCVでWebカメラの動体検知を実施する

Webカメラの画像に、日付とモーションファクター(全体の変化した割合)を表示させています。
モーションファクターが閾値以上になると、その時の画像を保存する仕組みになっています。

ウインドウ画面には、検知した時に「DETECTED」と赤文字が出るようにしました。

import datetime
import cv2

# 画像を保存するディレクトリ
save_dir  = './image/'

# ファイル名は「日付時刻 + fn_suffix」にする。
fn_suffix = 'motion_detect.jpg'

# カメラのキャプチャを開始
cap = cv2.VideoCapture(0)

# 縦と横の解像度指定
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 各ドットの変化を検知するしきい値
DOT_TH = 20

# モーションファクター(どれくらいの点に変化があったか)が
# どの程度以上なら記録するか。(0.0~1.0)
MOTHON_FACTOR_TH = 0.20

# 比較用のデータを格納
avg = None

while True:

    # 1フレームずつ取得する。
    ret, frame = cap.read()

    # フレームが取得できなかった場合は、画面を閉じる
    if not ret:
        break
    # データを取得した時刻
    dt_now = datetime.datetime.now()

    # ファイル名と画像中に埋め込む日付時刻
    datetime_str = dt_now.strftime('%Y-%m-%d %H:%M:%S') 
    f_name = dt_now.strftime('%Y%m%d%H%M%S%f') + "_" + fn_suffix

    # モノクロにする
    gray = cv2.cvtColor(frame, cv.COLOR_BGR2GRAY)

    # 比較基準用のフレームを取得する
    if avg is None:
        avg = gray.copy().astype("float")
        continue

    #「avg = (1 - 0.2) * avg + 0.2 * gray」で移動平均を更新
    cv2.accumulateWeighted(gray, avg, 0.2)
    # 現在のフレームと移動平均との差を計算
    frameDelta = cv2.absdiff(gray, cv.convertScaleAbs(avg))

    # デルタ画像を閾値処理を行う(差の有無で2値画像を作成)
    thresh = cv2.threshold(frameDelta, DOT_TH, 255, cv.THRESH_BINARY)[1]

    # モーションファクターを計算(全体としてどれくらいの割合が変化したか)
    motion_factor = thresh.sum() * 1.0 / thresh.size / DELTA_MAX 
    motion_factor_str = '{:.08f}'.format(motion_factor)

    # 画像に日付時刻を書き込み
    cv2.putText(frame,datetime_str,(25,50),cv.FONT_HERSHEY_SIMPLEX, 1.0,(255,255,255), 2)
    # 画像にmotion_factor値を書き込む
    cv2.putText(frame,motion_factor_str,(25,470),cv.FONT_HERSHEY_SIMPLEX, 1.0,(255,255,255), 2)

    # モーションファクターがしきい値を超えていれば動きを検知したことにする
    if motion_factor > MOTHON_FACTOR_TH:
        # ファイルに保存
        cv2.imwrite(save_dir + f_name, frame)
        print("DETECTED:" + f_name)
        
        # 画像に検知した旨のメッセージを書き込む
        cv2.putText(frame,"DETECTED",(400,470),cv.FONT_HERSHEY_SIMPLEX, 1.0,(0,0,255), 2)

    # ウィンドウに出力
    cv2.imshow('Frame - Press ESC or ENTER to exit.', frame)

    # 10ms間隔で更新する
    key = cv2.waitKey(10)

    # Escキーを入力されたら画面を閉じる
    if key == 27:
        break

    # Enterキーを入力されたら画面を閉じる
    if key == 13:
        break

# 後処理
cap.release()
cv2.destroyAllWindows()
検知した時のウインドウ画面
検知した時に保存された画像

画像を保存するだけではなく、メールを飛ばしたり、アラームを鳴らしたりもできそうです。
こういう便利なライブラリが無料で使えるなんて、すごいですね。

とりあえず、ここまで。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

20 + 19 =