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
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
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
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
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の知識不足のまま、色々と試してみました。結果が正しいのかも、判断が出来てないのが実情ですが、お疲れさまでした~