0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberryのカメラモジュールで静止画から動体検知

Posted at

Raspberry PI と言えば、色々な電子工作、という事で、今回カメラモジュールを使ってみたいと思います。
Raspberry OS が、Buster の頃は、カメラを接続して「motion」をinstallすれば終わり…だったのですが、Bullseye からカメラ周りの仕様変更にmotionが対応できないとの事で、試行錯誤で使っておりました。
現在では、Bookworm になり、OpenCV を勉強してみよう… の、今回です。

Raspberryの接続
カメラモジュールを取り付けます。ケーブルを取り付ける時、眼鏡を外す自分に歳を痛感します。(後何年続けられるかな?)力を入れ過ぎると、ポロっと壊れてしまうので、注意が必要です。

Step1.カメラで静止画(JPG)を保存します
Raspberry OS Lite で始めます。
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libcap-dev
sudo apt-get install libcamera-dev
sudo apt-get install python3-picamera2
sudo mkdir /test
sudo mkdir /test/camera
sudo chmod 777 -R /test
cd /test/camera

準備が出来たらプログラムを作りましょう。
vi createjpg.py

createjpg.py
import picamera2
import time

# カメラの設定
picam2 = picamera2.Picamera2()
picam2.start_preview()
config = picam2.create_preview_configuration(main={"size": (1920, 1080)})
picam2.configure(config)
picam2.start()

# 写真を撮影して保存
time.sleep(2)  # プレビュー開始後、2秒待つ
picam2.capture_file("image.jpg")  # 画像を image.jpg として保存

# カメラを停止
picam2.stop()

プログラムが出来たら実行してみましょう。
python createjpg.py

カメラモジュールを利用する時のメッセージがいくつか表示されます。
撮影したJPGファイルを確認しましょう。
ls -l (image.jpg の存在を確認しましょう)
カメラ撮影により、JPGファイルが作成されたのが解ります。

後続作業で画像を比較する為、先程の画像をコピーして2つにしておきます。
cp image.jpg image1.jpg

Step2.2つのJPGファイルから相違点を検知します
「motion」の代わりを「OpenCV」で求めるので、動体(2つの画像の差)を検知する…は必要な機能です。色々試してみました。下段に失敗作もあり、次に挙げる手法が、確実なのかも自信が無い状況ですが、データとして処理するには、扱い易いと思いました。

必要なパッケージをインストールします
sudo apt-get install libopencv-dev python3-opencv

プログラムを準備しましょう
vi chkjpg.py

chkjpg.py
import cv2
import numpy as np

# 画像を読み込む
image1 = cv2.imread('image1.jpg')
image2 = cv2.imread('image.jpg')

# グレースケールに変換
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)

# 画像を平滑化(ぼかし)
blur1 = cv2.GaussianBlur(gray1, (5, 5), 0)
blur2 = cv2.GaussianBlur(gray2, (5, 5), 0)

# 画像の差分を計算
diff = cv2.absdiff(blur1, blur2)

# 差分画像を二値化
_, thresh = cv2.threshold(diff, 50, 255, cv2.THRESH_BINARY)

# 輪郭を検出
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 小さな輪郭をフィルタリング
min_contour_area = 100  # 最小の輪郭面積
filtered_contours = [contour for contour in contours if cv2.contourArea(contour) > min_contour_area]

# 相違点の個数を表示
print(f'相違点の個数: {len(filtered_contours)}')

プログラムを実行しましょう。
python chkjpg.py

同じ画像を比較して相違点を確認しているので、「相違点の個数: 0」が表示されるはずです。
python createjpg.py
で撮影を実行し、image.pyとimage1.pyに、微妙な差を作ってから、再実行してみましょう。
python chkjpg.py
相違点の個数が、少し発見されましたかね。

【廃案1】ヒストグラムの比較で画像の差を検知する
2つの画像のヒストグラムを比較し、その相関係数を計算することで、画像間の類似度を評価してみます。

必要なパッケージをインストールします
sudo apt-get install libopencv-dev python3-opencv

プログラムを準備しましょう
vi chkHST.py

chkHST.py
import cv2
import numpy as np

def compare_images(img1_path, img2_path):
    # 画像を読み込む
    img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
    img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)

    # 画像のサイズを揃える
    img1 = cv2.resize(img1, (img2.shape[1], img2.shape[0]))

    # 画像のヒストグラムを計算
    hist1 = cv2.calcHist([img1], [0], None, [256], [0, 256])
    hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256])

    # ヒストグラムの正規化
    hist1 = cv2.normalize(hist1, hist1).flatten()
    hist2 = cv2.normalize(hist2, hist2).flatten()

    # ヒストグラムの相関係数を計算
    correlation = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)

    return correlation

if __name__ == "__main__":
    img1_path = "/test/camera/image1.jpg"
    img2_path = "/test/camera/image.jpg"

    similarity = compare_images(img1_path, img2_path)
    print(f"1.0は一致、差があると小さくなる: {similarity}")

プログラムを実行しましょう。
python chkHST.py

同じ画像で比較すると「1.0」が表示されるようですが、少しでも違うと、「1.0」にはならないようです。
ただ、少し物が入った程度では、ほぼ「1.0」なので、判断が難しい感じです。

【廃案2】構造的類似性指数(SSIM)で画像の差を検知する
SSIMは、人間の視覚系が画像をどのように知覚するかをモデル化し、輝度、コントラスト、構造の3つの要素に基づいて類似度を評価します。

必要なパッケージをインストールします
sudo apt-get install libopencv-dev python3-opencv
sudo apt-get install python3-skimage

プログラムを準備しましょう
vi chkSSIM.py

chkSSIM.py
import cv2
from skimage.metrics import structural_similarity as ssim
import numpy as np

# 画像を読み込む
image1 = cv2.imread('image1.jpg')
image2 = cv2.imread('image.jpg')

# グレースケールに変換
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)

# SSIMを計算し結果を表示
score, diff = ssim(gray1, gray2, full=True)
diff = (diff * 255).astype("uint8")
print("SSIMスコア: {:.4f}".format(score))

プログラムを実行しましょう。
python chkSSIM.py

ヒストグラムと同じように、同じ画像で比較すると「1.0」が表示されるようですが、少しでも違うと、「1.0」にはならないようです。
ヒストグラムと違い、少しの違いで、「1.0」から非常に小さな数値になるので、これも判断が難しい感じです。

以上、OpenCVの知見や画像系AIの知識不足のまま、色々と試してみました。結果が正しいのかも、判断が出来てないのが実情ですが、お疲れさまでした~

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?