Raspberry Pi定点カメラプロジェクト:カメラ設定編
前回の「Raspberry Pi定点カメラプロジェクト:ヘッドレスOSインストール/設定編」の続きです。
最終的には以下のYouTube動画のようなタイムラプス動画が作成できます。
需要あるの?この動画。。
ラズパイにカメラ装着
まずは、カメラをケーブルでRaspberry Pi Zero wに刺します。
今回、買ったカメラは Raspberry Pi Zero用スパイカメラ-adafruit 3508ですが、想定違いでケーブルを繋ぐとカメラがケースのカメラの穴と逆向きになりました。
しょうがないので厚紙でカバーしました。
でも、あまりにもカッコ悪いのでカメラをもう一つ買いました。
Raspberry Pi Camera Module V2 カメラモジュール
はい。無駄遣い認定!
こちらは綺麗にケースに収まります。 付属の白いケーブルじゃなくてRaspberry pi zero用のケーブルで繋ぐ必要があります。 繋ぐときは、コネクタのグレーの部分を引っ張り出して、ケーブル刺して、またグレーの部分を刺し戻します。カメラをラズパイに認識させる
つなぎ終わったら、
sudo raspi-config
次に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系
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))
この時間でカメラが勝手に明るさなどを自動補正してくれます。
このスクリプトを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で見るとチラチラと明るさが変わってしまっていた前回のものよりだいぶ良くなったように見えます。
例が違うからわかりにくい!
## 過去のcronを使ったやり方↓↓↓ 適当な名前 'cron.conf'等でファイルを作ります。$cat cron.conf
*/1 * * * * python3 pythonscript.py
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
....
sudo apt install ffmpeg
サクッと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
....
ffmpeg -f image2 -r 30 -i %10d.jpg -r:v 30 -an -s:v 1280x720 -pix_fmt yuv420p -vcodec libx264 timelapse.mp4
一時間を1分間隔で撮った場合などは ‘-r 10’、5分間隔で一週間撮りためた場合は’-r 50'等、ちょうどいい加減に調整しましょう。
mp4からgifへの変換もできます。 サイズを落とすために横幅320pxに落としています。
ffmpeg -i timelapse.mp4 -vf scale=320:-1 -r 10 timelapse.gif
暗くなったり明るくなったり自動補正機能のために統一感が出ていないので、この辺りの調整は今後の課題ですね。