タイムラプス(一定間隔で撮影)v2.0

ラズパイカメラを使って、月の動きや雲の変化など、長時間の変化を短時間ムービーで観察しよう

研究手順

  1. タイムラプスとは何か
  2. Raspberry Pi とカメラの準備
  3. Pythonコード1:一定間隔で写真を撮影する
  4. Pythonコード2:画像を繋げて、動画をつくる
  5. Pythonコード3:画像にタイトルを追加する
  6. 自分だけのタイムラプス作品をつくる(影, 雲, 植物 等)

タイムラプスとは何か

例えば1分間毎にカメラ撮影して、その画像をつなぎ合わせると短時間のビデオで長時間の変化を観察できる

  • 太陽の動き・影の変化を観察(1分間隔で1時間撮影。影の長さや向きが変わる様子)
  • 雲の動きの観察(10秒間隔で10分撮影。雲の形や風の流れがよくわかる)
  • 植物の成長観察(30分~1時間間隔で数日間撮影。)

Raspberry Pi とカメラの準備

ラズパイ基盤に、ラズパイ専用カメラを取り付ける

カメラがデバイスとして認識されていることを検査する

カメラデバイスが認識されるかテスト

$ vcgencmd get_camera

supported=1 detected=0, libcamera interfaces=0
         ↑ ここを見る
supported=1 detected=0 #認識されてない
supported=1 detected=1 #認識された

カメラで撮影できるかテスト

$ raspistill -o test.jpg

Pythonコード1:一定間隔で写真を撮影する

目標:Raspberry Pi と Python を使って 一定間隔で写真を撮影するプログラム を作れるようになる

前提:CoderDojo青梅のSDカードを使っていれば、カメラ撮影のOpenCVライブラリはインストール済み

機能:time.sleep() を使って 5 秒ごとに撮影。ファイル名は日時入りで保存。画像の向きはcv2.rotateで調整。

pythonディレクトリで、新しいファイルを作成する[$ nano timelapse.py]

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import cv2
import os
import time
import datetime

# 保存先ディレクトリ
SAVE_DIR = "/home/pi/python/timelapse_pics/"
INTERVAL = 5   # 撮影間隔(秒)あとで変更可能

def main():
    # 保存フォルダがなければ作成
    if not os.path.exists(SAVE_DIR):
        os.makedirs(SAVE_DIR)

    # カメラを起動
    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        print("カメラが見つかりません。USBカメラを確認してください。")
        return

    print("タイムラプス撮影を開始します。Ctrl+C で終了できます。")

    try:
        count = 0
        while True:
            ret, frame = cap.read()
            if not ret:
                print("画像が取得できませんでした。")
                break

            # 必要なら回転(あなたの環境に合わせて)
            frame = cv2.rotate(frame, cv2.ROTATE_180)

            # ファイル名(日時入り)
            now = datetime.datetime.now()
            filename = "pic_{0:%Y%m%d_%H%M%S}.jpg".format(now)
            filepath = os.path.join(SAVE_DIR, filename)

            # 保存
            cv2.imwrite(filepath, frame)
            count += 1

            print(f"{count}枚目を撮影しました:{filepath}")

            # 次の撮影まで待つ
            time.sleep(INTERVAL)

    except KeyboardInterrupt:
        print("\n撮影を終了します。")

    finally:
        cap.release()
        cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

保存したら実行してカメラ映像を撮影する。

$ python3 timelapse.py

ディレクトリ[/home/pi/python/timelapse_pics]に保存されている、画像ファイル[pic_xxxx.jpg]を確認する。

(カスタマイズ)撮影間隔を変更するには秒数を変更する

INTERVAL = 10   # 10秒ごとに撮影

Pythonコード2:画像を繋げて、動画をつくる

目標:撮影した画像をつなげて タイムラプス動画を生成 できる

機能:OpenCV の cv2.VideoWriter を使う。画像サイズを自動取得して、FPS動画速度(1秒当たりの画像数)を指定してビデオ作成

pythonディレクトリで、新しいファイルを作成する[$ nano timelapse_make_movie.py]

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import cv2
import os
import glob

# 画像が保存されているフォルダ
IMG_DIR = "/home/pi/python/timelapse_pics/"

# 出力する動画ファイル名
OUTPUT_FILE = "/home/pi/python/timelapse_timelapse.mp4"

# 動画のフレームレート(1秒あたりの画像枚数)
FPS = 30


def main():
    # 画像ファイル一覧を取得(日時順に並ぶようにソート)
    img_files = sorted(glob.glob(os.path.join(IMG_DIR, "*.jpg")))

    if len(img_files) == 0:
        print("画像が見つかりません。撮影スクリプトで画像を作成してください。")
        return

    print(f"{len(img_files)} 枚の画像を動画にまとめます。")

    # 最初の画像からサイズを取得
    first_img = cv2.imread(img_files[0])
    height, width, channels = first_img.shape

    # 動画ファイルの設定(mp4)
    fourcc = cv2.VideoWriter_fourcc(*"mp4v")
    video = cv2.VideoWriter(OUTPUT_FILE, fourcc, FPS, (width, height))

    # ←←← あとで、ここにオープニング追加コードを入れる!

    # 画像を順番に動画へ追加
    for i, img_path in enumerate(img_files):
        img = cv2.imread(img_path)
        if img is None:
            print(f"読み込み失敗: {img_path}")
            continue

        video.write(img)
        print(f"{i+1}/{len(img_files)} 枚目を追加しました")

    video.release()
    print(f"動画を作成しました:{OUTPUT_FILE}")


if __name__ == "__main__":
    main()

保存したら実行して画像をつなぎ合わせて動画を作成する。

$ python timelapse_make_movie.py

動画を再生してみる。VScodeの場合は、Windowsへダウンロードする。

(カスタマイズ)1秒当たりの画像数FPSを変更する

FPS = 10

Pythonコード3:画像にタイトルを追加する

連続した画像の最初にタイトルを追加します。図形やテキストは自由に改造してください。

目的:動画のオープニングタイトル。極めれば、動画編集アプリもつくれる。

前提:撮影した静止画ファイル名を変更すること「pic_20260209_120051.jpg」

pythonディレクトリで、新しいファイルを作成する[$ nano timelapse_add_title.py]

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import cv2

# 画像が保存されているフォルダ
IMG_DIR = "/home/pi/python/timelapse_pics/"

# 読み込む画像ファイル名
IMG_FILE = "pic_20260209_120051.jpg"

def main():
    # 画像を読み込む(pythonでのフルパス結合方法。IMG_DIR + IMG_FILEでも動くが/忘れを自動調整するので安心)
    img_path = os.path.join(IMG_DIR, IMG_FILE)
    img = cv2.imread(IMG_FILE)

    if img is None:
        print("画像が読み込めませんでした。ファイル名を確認してください。")
        return

    # -----------------------------
    # 図形や文字を描くサンプル
    # -----------------------------

    # ① 直線(青色、太さ3)
    cv2.line(img, (50, 50), (300, 50), (255, 0, 0), 3)

    # ② 四角形(赤色、枠線のみ、太さ3)
    cv2.rectangle(img, (50, 100), (300, 250), (0, 0, 255), 3)

    # ③ 四角形(緑色、塗りつぶし)
    cv2.rectangle(img, (350, 100), (550, 250), (0, 255, 0), -1)

    # ④ 円(黄色、枠線のみ、太さ5)
    cv2.circle(img, (200, 350), 80, (0, 255, 255), 5)

    # ⑤ 円(紫色、塗りつぶし)
    cv2.circle(img, (450, 350), 60, (255, 0, 255), -1)

    # ⑥ テキスト(白色)
    cv2.putText(
        img,
        "Hello Timelapse!",
        (50, 450),
        cv2.FONT_HERSHEY_SIMPLEX,
        1.2,
        (255, 255, 255),
        3,
        cv2.LINE_AA
    )

    # -----------------------------
    # 保存
    # -----------------------------
    out_name = os.path.join(IMG_DIR, "edited_pic.jpg")
    cv2.imwrite(out_name, img)
    print(f"画像を保存しました:{out_name}")

if __name__ == "__main__":
    main()

オープニング画像を追加する

pythonコードを改造する[$ nano timelapse_make_movie.py]
「←←← ここにオープニング追加コードを入れる!」という場所に下記を追加する

    # --- オープニング画像を3秒表示する ---
    opening_path = os.path.join(IMG_DIR, "edited_pic.jpg")
    opening_img = cv2.imread(opening_path)

    if opening_img is not None:
        # サイズが違う場合は動画サイズに合わせてリサイズ
        if opening_img.shape[0] != height or opening_img.shape[1] != width:
            opening_img = cv2.resize(opening_img, (width, height))

        opening_frames = FPS * 3  # 3秒分

        for _ in range(opening_frames):
            video.write(opening_img)

        print("オープニング画像を追加しました(3秒)")
    else:
        print("オープニング画像が見つかりませんでした。スキップします。")

タイトル編集するための引数

cv2.line(img, (50, 50), (300, 50), (255, 0, 0), 3) を説明する
画像サイズは、640×480の場合を例にしている。
VGA 640×480
HD 1280×720

  • img は、線を追加する画像
  • 最初の (50, 50) は、線のスタート位置
    ╋ 0 → 100
    0

    100
  • ふたつ目の (300, 50) は線の終点 X, Y
  • 三つ目の (255, 0, 0) は線の色 B G R の順番。この場合は青色。
  • 最後の 3 は線の太さ

まとめると

  • 直線 cv2.line(img, (x1, y1), (x2, y2), (B, G, R), 太さ)
  • 四角形 cv2.rectangle(img, (x1, y1), (x2, y2), (B, G, R), 太さ) …ただし太さ = -1 で塗りつぶし
  • 円 cv2.circle(img, (x, y), 半径, (B, G, R), 太さ) …ただし太さ = -1 で塗りつぶし
  • 楕円 cv2.ellipse(img, (x, y), (長半径, 短半径), 角度, 開始角度, 終了角度, (B, G, R), 太さ) …# 中心, # 半径(横, 縦)
  • 多角形(polylines)
    pts = np.array([[x1, y1], [x2, y2], [x3, y3]], np.int32)
    pts = pts.reshape((-1, 1, 2))
    cv2.polylines(img, [pts], 閉じるかどうか(True/False), (B, G, R), 太さ)

自分だけのタイムラプス作品をつくる(影, 雲, 植物 等)

太陽の動きによる影の変化など、観察するプロジェクトを発表する。
太陽を撮影しちゃダメだよ。カメラが壊れちゃうので。

コメントを残す