Raspberry Pi定点カメラプロジェクト:カメラ設定編

thumbnail for this post

前回の「Raspberry Pi定点カメラプロジェクト:ヘッドレスOSインストール/設定編」の続きです。
最終的には以下のYouTube動画のようなタイムラプス動画が作成できます。

需要あるの?この動画。。

ラズパイにカメラ装着

まずは、カメラをケーブルでRaspberry Pi Zero wに刺します。
今回、買ったカメラは Raspberry Pi Zero用スパイカメラ-adafruit 3508ですが、想定違いでケーブルを繋ぐとカメラがケースのカメラの穴と逆向きになりました。

Adafruitカメラ 3508逆向き

Adafruit 3508逆向き


しょうがないので厚紙でカバーしました。
ラズパイカメラお手製カバー

お手製カバー


でも、あまりにもカッコ悪いのでカメラをもう一つ買いました。
Raspberry Pi Camera Module V2 カメラモジュール

はい。無駄遣い認定!

こちらは綺麗にケースに収まります。
ラズパイカメラv2

ラズパイカメラv2

付属の白いケーブルじゃなくてRaspberry pi zero用のケーブルで繋ぐ必要があります。
右側のケーブルで繋ぐ

右側のケーブルで繋ぐ

繋ぐときは、コネクタのグレーの部分を引っ張り出して、ケーブル刺して、またグレーの部分を刺し戻します。
Raspberry piカメラコネクタ

カメラコネクタ


カメラをラズパイに認識させる

つなぎ終わったら、

sudo raspi-config
でカメラを認識させます。 Interfacing Optionを選択
ラズパイコンフィグInterfacing Option

Interfacing Option


次にCameraを選択
ラズパイCamera設定

Camera


Pythonから写真を撮る

必要なものをインストールします。

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python3-pip
sudo pip3 install picamera
sudo pip3 install pathlib #ディレクトリいじり系
sudo pip3 install paramiko scp #SCP系
pythonスクリプト例 raspberry pi内に写真を貯める場合
import picamera
import datetime
import time
from pathlib import Path

now = datetime.datetime.now()
p = Path('/home/pi/photos/')
file_name = now.strftime('%Y%m%d%H%M') + '.jpg'

if p.exists()!=True:
  p.mkdir()

with picamera.PiCamera() as camera:
#  camera.resolution = (2592,1944)
  camera.resolution = (1280 ,720)
  camera.exif_tags['IFD0.Copyright'] = 'Copyright 2019 heisaku@comichi.com'
  time.sleep(2) #このsleep重要
  camera.capture(str(p/file_name))
カメラのインスタンスを作成してからsleepで2秒ほど待ってやる必要があります。
この時間でカメラが勝手に明るさなどを自動補正してくれます。
このスクリプトをcronで定期的に実行すれば、ラズパイ内に年月日時分をファイル名にもつjpgファイルが出来上がります。

2020年1月3日更新

昨年の12月の段階(記事は下の方に残してあります)ではcronを使ったやり方で定期的に写真を撮っていましたが、

暗くなったり明るくなったり自動補正機能のために統一感が出ていないので、この辺りの調整は今後の課題ですね。

と書いている通り、画面の明るさがcronで起動されるたびに変わってしまう印象がありました。
そこで、改良版としてpicameraのcapture_continuous機能を使って見ました。 (2020/01/09: さらにlosslessフォーマットのpngに変えました)
(2020/02/05: さらにssh接続エラーが起こるとプロセスごと落ちちゃうので例外処理入れました)

#!/usr/bin/python3
from picamera import PiCamera
from time import sleep
from datetime import datetime, timedelta
from pathlib import Path
from paramiko import SSHClient
from scp import SCPClient

def wait_func(min=1):
    next_min = (datetime.now() + timedelta(minutes=min)).replace(second=1, microsecond=0)
    delay = (next_min - datetime.now()).seconds
    sleep(delay)

def take_photos(min_every, howmany=None, send=False):
    p = Path('/home/pi/photos/')
    if p.exists()!=True:
        p.mkdir()
    wait_func(min_every)
    with PiCamera() as camera:
        camera.resolution = (1280 ,720)
        camera.exif_tags['IFD0.Copyright'] = 'Copyright 2019 heisaku@comichi.com'
        wait_func(min_every)
        for i, filename in enumerate(camera.capture_continuous(str(p/'{timestamp:%Y%m%d%H%M%S}.png'),'png')):
            print('Captured %s' % filename)
            if(send==True):
                send_to_server(p)
            if((howmany is not None) and (howmany == i)):
                break
            wait_func(min_every)

def send_to_server(p):
    try:
        with SSHClient() as ssh:
            ssh.load_system_host_keys()
            ssh.connect(hostname='<host IP>', port=22, username='<user name>')
            scp = SCPClient(ssh.get_transport())
            for f in p.glob('*.png'):
                scp.put(f,'/save location path/') #(file, remote_path)
                f.unlink() #転送し終わったら消す
    except Exception as e:
        print("ssh connection error:", e.args)
	return

if __name__ == "__main__": # スクリプトとして実行された場合
  import sys
  if len(sys.argv)<2:
      print("python3 take_photos <min_every> <howmany> <send>")
      exit()
  sys.argv.pop(0)
  take_photos(*list(map(eval,sys.argv)))

何分おきに何枚撮るか、撮った写真をSSH転送するか、などをオプション設定できるようにしていますので参考にしていただければと思います。
以下のgifで見るとチラチラと明るさが変わってしまっていた前回のものよりだいぶ良くなったように見えます。

今回のcapture_continuousを使った例

今回のcapture_continuousを使った例


前回のcronで毎回カメラ起動した例

前回のcronで毎回カメラ起動した例

例が違うからわかりにくい!

## 過去のcronを使ったやり方↓↓↓ 適当な名前 'cron.conf'等でファイルを作ります。
$cat cron.conf
*/1 * * * * python3 pythonscript.py
```*/1```は1分ごとに実行を意味しています。 間隔を延ばしたい場合 ```*/5```等に書き換えると良いでしょう。 ファイルができたら、以下のコマンドで設定を反映させます。
crontab cron.conf
止めるときは
crontab -r
です。

jpegファイルから動画への変換

(pngの時も同様:jpgをpngに読み替えてください)
ファイルを受け取るサーバでは、以下のようにファイルが出来上がっています。
ファイルがラズパイ内にある場合はscpなどで適当な動画変換用のサーバーに転送することをお勧めします。

$ls /data/photos/
201912300950.jpg  201912300958.jpg  201912301006.jpg  201912301014.jpg  201912301022.jpg  201912301030.jpg  201912301038.jpg  201912301046.jpg
201912300951.jpg  201912300959.jpg  201912301007.jpg  201912301015.jpg  201912301023.jpg  201912301031.jpg  201912301039.jpg  201912301047.jpg
201912300952.jpg  201912301000.jpg  201912301008.jpg  201912301016.jpg  201912301024.jpg  201912301032.jpg  201912301040.jpg  201912301048.jpg
....
まずは、変換に使うアプリケーション’ffmpeg'をインストールします。
sudo apt install ffmpeg
ffmpegは連続する数字のファイル名を持つjpgを対象に変換するので、日付文字列のファイル名を変換してやる必要があります。
サクッとpythonで書くとこんな感じです。
from pathlib import Path
import shutil
p = Path('/data/photos/')
p_work = Path('/data/photo_work/')
i = 0
for f in sorted(p.glob('*.jpg'), key=lambda path: int(path.stem)):
    filename = format(i,'010')+'.jpg'
    shutil.copyfile(f,p_work/filename)
    i = i + 1
ファイル名を数字に直してソートすることで、順序を保証しています。
ファイル名が以下のように数字順になれば後は動画への変換です。
$ls /data/photo_work/
0000000000.jpg  0000000005.jpg  0000000010.jpg  0000000015.jpg  0000000020.jpg  0000000025.jpg  0000000030.jpg  0000000035.jpg  0000000040.jpg  0000000045.jpg  0000000050.jpg
0000000001.jpg  0000000006.jpg  0000000011.jpg  0000000016.jpg  0000000021.jpg  0000000026.jpg  0000000031.jpg  0000000036.jpg  0000000041.jpg  0000000046.jpg  0000000051.jpg
0000000002.jpg  0000000007.jpg  0000000012.jpg  0000000017.jpg  0000000022.jpg  0000000027.jpg  0000000032.jpg  0000000037.jpg  0000000042.jpg  0000000047.jpg  0000000052.jpg
....
変換は、jpgファイルのある場所で以下のコマンドです。
ffmpeg -f image2 -r 30 -i %10d.jpg -r:v 30 -an -s:v 1280x720 -pix_fmt yuv420p -vcodec libx264 timelapse.mp4
‘-r 30'の数字を減らせばスローな動画、増やせば早い動画になります。
一時間を1分間隔で撮った場合などは ‘-r 10’、5分間隔で一週間撮りためた場合は’-r 50'等、ちょうどいい加減に調整しましょう。
mp4からgifへの変換もできます。 サイズを落とすために横幅320pxに落としています。
ffmpeg -i timelapse.mp4 -vf scale=320:-1 -r 10 timelapse.gif
冬といえばボードゲーム!の例

冬といえばボードゲーム!の例

暗くなったり明るくなったり自動補正機能のために統一感が出ていないので、この辺りの調整は今後の課題ですね。

投げ銭していただける場合は、amazonで15円からできます。宛先はheisakuあっとcomichi.comで。

マイナスは入れられないの?

comments powered by Disqus