welcom ! Handel home

2025年3月20日 星期四

影片與 IMU 資料的同步配對 (視覺-慣性 SLAM(Visual-Inertial SLAM))

 影片與 IMU 資料的同步配對,通常是以「時間戳記(timestamp)」來對齊的,這在 視覺-慣性 SLAM(Visual-Inertial SLAM) 或視覺導航任務中非常關鍵。


🕒 為什麼要用時間戳對齊?

因為:

  • 相機畫面(影片)是每 30FPS 或 60FPS 拍攝
  • IMU 資料是高頻率(例如 100Hz~1000Hz)記錄的

→ 若要結合這兩個訊號,你必須知道「這一幀畫面」對應的是哪一段 IMU 資料,才能讓系統準確估算機器人運動狀態。


📁 一般常見的同步資料格式(資料集範例)

🎬 視覺資料(影片或影格序列)

bash
frames/ ├── frame_000000.png ├── frame_000001.png └── ...

對應的時間戳記檔案(rgb.txtimages.txt):

txt
# timestamp filename 0.000000 frame_000000.png 0.033333 frame_000001.png ...

📈 IMU 資料

一般為 CSV 格式:

csv
# timestamp, acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z 0.000010, 0.1, 0.2, 9.8, 0.01, 0.02, 0.03 0.000020, ...

🔗 對齊方式(時間同步)

方法 A:手動插值同步

  • 每張影格抓對應前後最近的 IMU 兩筆資料
  • 線性插值 IMU 值與畫面時間對齊

方法 B:使用 IMU 頻率近似同步

  • 將 IMU 資料切段,對齊每張影格前後 ±dt 範圍的資料,作為輸入 batch

方法 C:ROS 時間戳同步

  • 透過 message_filters.ApproximateTimeSynchronizer 自動同步 /camera/image_raw/imu/data

🧪 若你是用影片 + 單獨 IMU log

你要做的事情是:

  1. 解析影片 → 抽出每張影格 + 加上「時間戳」

    • 使用 cv2.CAP_PROP_POS_MSEC 拿到毫秒時間
  2. 讀入 IMU 資料(CSV)

    • 根據影格的時間戳 t_frame 找最近的 IMU 資料區間
  3. 將影格與該時刻 IMU 對應起來

    • 用於 Visual-Inertial SLAM 或 RL policy 的輸入

🛠️ 若你使用 ROS 環境:

建議透過 rosbag 記錄影片與 IMU:

bash
rosbag record /camera/image_raw /imu/data

→ ROS 會自動帶入 header.stamp,你就可以在下游模組直接同步這兩個話題資料。


✅ 總結:

問題答案
是否需用時間對齊?✅ 是的,使用 timestamp 對齊畫面與 IMU
一定要 ROS 嗎?不一定,可用 CSV + Python 自行處理
時間單位?通常為秒(浮點數),有些系統用毫秒(ms)或納秒(ns)
ROS 下最簡方式?使用 rosbag 記錄影像 + IMU,自動同步處理

如果你提供:

  • MP4 影片檔
  • IMU CSV(含時間) 我可以幫你自動對齊時間點,並輸出成 ROS bag、圖像序列+IMU 或 SLAM-ready 格式(如 EuRoC dataset 風格)。

#寫一份「影片 + IMU CSV → 對齊輸出」的 Python 處理腳本

以下是你需要的 「影片 + IMU CSV → 對齊輸出」的 Python 腳本,功能包括:

  1. 將 MP4 影片抽成影格並加上時間戳
  2. 從 IMU .csv 檔讀入加速度與角速度資料
  3. 為每張影格找到最近的 IMU 資料並對齊
  4. 輸出:
    • 影格圖像(存入資料夾)
    • rgb.txt(影格與時間對應表)
    • synced_imu.csv(與每張影格對應的 IMU 資料)

🐍 sync_video_imu.py

python
import cv2 import os import pandas as pd import numpy as np from pathlib import Path def extract_frames(video_path, output_dir): cap = cv2.VideoCapture(video_path) fps = cap.get(cv2.CAP_PROP_FPS) print(f"[INFO] Video FPS: {fps}") timestamps = [] frame_dir = Path(output_dir) / "frames" frame_dir.mkdir(parents=True, exist_ok=True) frame_idx = 0 while True: ret, frame = cap.read() if not ret: break timestamp = frame_idx / fps filename = f"frame_{frame_idx:06d}.png" filepath = frame_dir / filename cv2.imwrite(str(filepath), frame) timestamps.append((timestamp, filename)) frame_idx += 1 cap.release() return timestamps, frame_dir def load_imu_csv(imu_csv_path): imu_df = pd.read_csv(imu_csv_path) # 確保 timestamp 欄位為浮點數 imu_df["timestamp"] = imu_df["timestamp"].astype(float) imu_df.sort_values("timestamp", inplace=True) return imu_df def match_imu_to_frames(frame_timestamps, imu_df): synced_imu = [] imu_ts = imu_df["timestamp"].values for ts, fname in frame_timestamps: idx = np.argmin(np.abs(imu_ts - ts)) imu_row = imu_df.iloc[idx] synced_imu.append({ "timestamp": ts, "frame": fname, **imu_row.drop("timestamp").to_dict() }) return pd.DataFrame(synced_imu) def save_rgb_txt(frame_timestamps, output_path): with open(output_path, "w") as f: f.write("# timestamp filename\n") for ts, fname in frame_timestamps: f.write(f"{ts:.6f} {fname}\n") def main(): # ========== 設定區 ========== video_path = "your_video.mp4" # ← 影片路徑 imu_csv_path = "your_imu.csv" # ← IMU CSV 路徑 output_dir = "output_dataset" # ← 輸出資料夾 # ============================ print("[1] 解析影片中...") frame_timestamps, frame_dir = extract_frames(video_path, output_dir) print("[2] 讀取 IMU 資料...") imu_df = load_imu_csv(imu_csv_path) print("[3] 進行時間對齊...") synced_df = match_imu_to_frames(frame_timestamps, imu_df) print("[4] 輸出資料中...") save_rgb_txt(frame_timestamps, Path(output_dir) / "rgb.txt") synced_df.to_csv(Path(output_dir) / "synced_imu.csv", index=False) print("✅ 處理完成!") print(f"📁 圖像輸出:{frame_dir}") print(f"📄 影格清單:{output_dir}/rgb.txt") print(f"📈 同步 IMU :{output_dir}/synced_imu.csv") if __name__ == "__main__": main()

📥 IMU CSV 格式範例(your_imu.csv

csv
timestamp,acc_x,acc_y,acc_z,gyro_x,gyro_y,gyro_z 0.00001,0.1,0.2,9.8,0.01,0.02,0.03 0.01001,0.1,0.2,9.7,0.01,0.02,0.03 ...

📁 輸出結果

output_dataset/ ├── frames/ │ ├── frame_000000.png │ ├── ... ├── rgb.txt ← 影格對應時間 ├── synced_imu.csv ← 每張影格對應的最近 IMU 數據

✅ 接下來你可以:

  • frames/ + rgb.txt + synced_imu.csv 打包成 EuRoC-style dataset
  • 導入 ORB-SLAM3 / RTAB-Map / 自建 Visual-Inertial 模型做訓練
  • 或使用這組資料進行強化學習視覺導航訓練

需要我幫你寫接下來的 ROS bag 產生器 or SLAM 使用範例嗎?

你也可以把 CSV、影片給我 sample,我可以直接幫你測試同步結果 




沒有留言: