Uncategorized PR

PythonとOpenCVでフトアゴヒゲトカゲの咀嚼を可視化してみた

フトアゴヒゲトカゲがゲージに入って外を見ている
記事内に商品プロモーションを含む場合があります

フトアゴヒゲトカゲ「すみそ」がコオロギを食べる様子を、Python+OpenCVで解析。
動画の動きを数値化し、咀嚼のリズムをグラフで見える化しました。


🎥 本日の素材(動画)

  • 動画名20251026_sumiso_eating_v01.MP4
  • YouTubehttps://youtu.be/g3_j40-kctA
  • 撮影時間:約3分
  • 環境メモ:温度 バスキングスポット39度 クールスポット29度くらい

🎯 目的

  • 行動観察(採食行動)の定量化
  • 咀嚼回数や咀嚼間隔(テンポ)を記録し、日々の比較や健康状態の可視化に活かす。

⚙️ 手順の概要

  1. 動画をOpenCVで読み込み、フレーム間差分から「動きの強さ」を算出
  2. SciPyのfind_peaks咀嚼のピークを自動検出
  3. 平均・最長・最短の咀嚼間隔を計算
  4. 結果をCSV出力し、SQLiteへ登録(研究データベース化)
  5. Matplotlibで可視化(時系列/ヒストグラム)

💻 使用コード(抜粋)

1️⃣ Motion Intensity(動きの強さ)を算出

import cv2, numpy as np, matplotlib.pyplot as plt

video_path = "../../videos/raw/20251026_sumiso_eating_v01.MP4"
cap = cv2.VideoCapture(video_path)
fps = cap.get(cv2.CAP_PROP_FPS) or 30.0

ret, prev = cap.read()
prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)
motion_values = []

while True:
    ret, frame = cap.read()
    if not ret:
        break
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    diff = cv2.absdiff(prev_gray, gray)
    motion = float(np.sum(diff)) / diff.size
    motion_values.append(motion)
    prev_gray = gray

cap.release()

plt.figure(figsize=(10,4))
plt.plot(motion_values)
plt.title("Motion Intensity Over Time (Sumiso Eating)")
plt.xlabel("Frame")
plt.ylabel("Motion Level")
plt.show()


2️⃣ 咀嚼ピーク検出(自動カウント)

from scipy.signal import find_peaks
import numpy as np

# 平滑化
win = max(3, int(fps * 0.2))
kernel = np.ones(win) / win
mv = np.array(motion_values)
mv_smooth = np.convolve(mv, kernel, mode="same")

# ピーク検出
thr = np.percentile(mv_smooth, 80)
min_dist = max(5, int(fps * 0.3))
peaks, props = find_peaks(mv_smooth, height=thr, distance=min_dist)

plt.figure(figsize=(10,4))
plt.plot(mv, label="Motion (raw)")
plt.plot(mv_smooth, label="Motion (smoothed)")
plt.plot(peaks, mv_smooth[peaks], "ro", label="Detected chews")
plt.legend()
plt.title(f"Detected Chews: {len(peaks)} | fps={fps:.1f}")
plt.xlabel("Frame")
plt.ylabel("Motion Level")
plt.show()

# 咀嚼間隔(秒)
intervals = np.diff(peaks) / fps
print(f"平均咀嚼間隔: {np.mean(intervals):.2f} 秒")
print(f"最長咀嚼間隔: {np.max(intervals):.2f} 秒")
print(f"最短咀嚼間隔: {np.min(intervals):.2f} 秒")


📊 結果サマリ

  • 平均咀嚼間隔:1.54 秒
  • 最長咀嚼間隔:38.10 秒
  • 最短咀嚼間隔:0.27 秒

メモ

  • すみそは1.5秒周期の安定したテンポで咀嚼
  • 長い休憩(嚥下・観察時間)を挟む
  • 短い間隔は「噛み直し」のような連続動作

🧾 データ保存

  • CSV:data/csv/sumiso_20251026_chew_data.csv
  • DB:data/sql/karashi_lab.db(テーブル:eating_logs

1動画あたりの
avg_interval / max / min / fps / total_chews をSQLに登録。
今後、日付や個体ごとの分析・比較に活用。


🔭 今後の展開

  • 「からし」との比較(平均咀嚼テンポや休止時間)
  • 咀嚼テンポ分布(ヒストグラム)で安定性を分析
  • 気温・照明・餌種類の条件も変えて、多変量分析へ発展予定

📁 ディレクトリ構成

KarashiLab/
├── videos/
│   └── raw/20251026_sumiso_eating_v01.MP4
├── data/
│   ├── csv/
│   └── sql/karashi_lab.db
├── scripts/
│   └── notebooks/chew_analysis_sumiso.ipynb
└── docs/
    ├── observation_log.xlsx
    └── images/sumiso_motion_graph.png