Rasberry PiでUSBカメラで写真を撮影してFTPアップロードする方法

Rasberry PiでUSBカメラで写真を撮影してFTPアップロードする方法をご紹介します。

静止画取得~FTPアップロード~静止画削除を行います。

条件

  • raspberry pi 3
  • USBカメラ
  • Python 3.6.4

事前準備

USBカメラ接続

USBカメラをraspberry piに接続します。

今回は「LOGICOOL HDウェブカム C525」を使用しました。

USBカメラは上記以外のものでも大丈夫だと思われます。

コマンドラインで「lsusb」を実行します。

pi@raspberrypi:~/camera_test $ lsusb
Bus 001 Device 080: ID 046d:0826 Logitech, Inc. 
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

「Bus 001 Device 080: ID 046d:0826 Logitech, Inc. 」という表示があり、USBカメラが認識されていることがわかります。

fswebcamのインストール

静止画を取得するための「fswebcam」というパッケージをインストールします。

$ sudo apt update
$ sudo apt install fswebcam

以上で事前準備は完了です。

写真撮影&FTPアップロード

写真撮影してから、指定のサーバーに写真をアップロードするため、Pythonでプログラムを作成します。

ソース

全体のソースは以下の通りです。
(cameraTest.pyという名前で保存します。)

# cameraTest.py


## FTPアップロードサンプル
import subprocess
import sys
import os
import time
from datetime import datetime as dt
from ftplib import FTP
import ftplib
from logging import getLogger, StreamHandler, Formatter, DEBUG


## ログ出力設定
logger = getLogger("Camera Test")
logger.setLevel(DEBUG)
stream_handler = StreamHandler()
stream_handler.setLevel(DEBUG)
formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)

## 接続先ホスト
HOST = 'hostName'
PORT = 21
USER = 'user'
PASSWORD = 'password'
DIRECTORY = 'test'

## アップロードファイル名の生成
PREFIX = 'c1_'

## ネットワーク設定がおかしい場合の回避策
_old_makepasv = FTP.makepasv
def _new_makepasv(self):
    host,port = _old_makepasv(self)
    host = self.sock.getpeername()[0]
    return host,port
FTP.makepasv = _new_makepasv


def command(cmd):
  """
  Exec command
  """
  try:
    result = subprocess.run(cmd, shell=True, check=True,
                  stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                  universal_newlines=True)
    for line in result.stdout.splitlines():
      yield line
  except subprocess.CalledProcessError:
    logger.error('Command [' + cmd + '] was failed.', file=sys.stderr)
    sys.exit(1)


def upload(fileName):
  """"
  FTP接続、ファイルアップロード
  """
  logger.debug('== Start FTP ==')
  with FTP() as ftp:
    try:
      ftp.connect(HOST, PORT)   # ホスト、ポートを指定して接続
      ftp.login(USER, PASSWORD) # ユーザID、パスワードを指定してログイン
      ftp.cwd(DIRECTORY)        # 指定のディレクトリに移動
      with open(fileName, 'rb') as f:
        ftpResult = ftp.storbinary('STOR ' + fileName, f) # 対象ファイルをアップロード
        logger.debug(ftpResult)
    except ftplib.all_errors as e:
      logger.error('FTP error = %s' % e)
    else:
      logger.debug('FTP success.')	
  logger.debug('== End FTP ==')

  if ftpResult == '226 Transfer complete.':
    return True
  else:
    return False


def main():
  """
  main関数
  """
  fileName = PREFIX + dt.now().strftime('%Y%m%d_%H%M%S') + '.jpg'
  cmd = 'fswebcam -r 800x600 --no-banner ' + fileName  # 実行するコマンド

  num = 0
  while num < 10:
    if os.path.isfile(fileName):
      logger.info('exits.')
      break
    else:
      logger.debug('not exits.')

    for result in command(cmd):
      logger.info(result)

    time.sleep(3)  # wait output
    num += 1
  
  if num == 10:
    logger.error('File not found.')
    return

  if upload(fileName):  # File Upload
    logger.info('Upload success.')
    cmd = 'rm ' + fileName
    logger.debug(cmd)
    for result in command(cmd):  # Delete Image
      logger.info(result)
  else:
    logger.warning('Upload failed.')


if __name__ == "__main__":
    main()

解説

ソースの概略(main関数)は以下の通りです。

  • 撮影画像のファイル名(fileName)を現在日時で作成します。
  • fswebcamコマンドを実行し、静止画像を取得します。
    • -rオプションで画像サイズを指定し、–no-bannerオプションで画像からバナーを削除します。
  • 静止画像取得の処理に少し時間がかかる&失敗することもあるため、whileループでsleep()を入れながら撮影のリトライを行います。
    • 10回失敗した場合、エラーとします。
  • 静止画像の取得に成功した場合、指定サーバーへFTPアップロードを行います。
  • FTPアップロードに成功した場合、静止画像をrasberry piから削除します。

注意事項

静止画像の取得は、短い時間で連続して実施することは出来ないようです。

一度、静止画像を取得した後、カメラの準備処理が行われるため、数秒間待つ必要があります。

実行結果

処理成功

処理に成功した場合、以下のような出力となります。

pi@raspberrypi:~/camera_test $ python3 cameraTest.py 
2019-12-12 16:49:29,736 - Camera Test - DEBUG - not exits.
2019-12-12 16:49:34,197 - Camera Test - INFO - exits.
2019-12-12 16:49:34,197 - Camera Test - DEBUG - == Start FTP ==
2019-12-12 16:49:35,422 - Camera Test - DEBUG - 226 Transfer complete.
2019-12-12 16:49:35,422 - Camera Test - DEBUG - FTP success.
2019-12-12 16:49:35,468 - Camera Test - DEBUG - == End FTP ==
2019-12-12 16:49:35,469 - Camera Test - INFO - Upload success.
2019-12-12 16:49:35,469 - Camera Test - DEBUG - rm c1_20191212_164929.jpg

撮影失敗の場合

撮影に失敗した場合(静止画取得に10回失敗)、以下のような出力となります。

pi@raspberrypi:~/camera_test $ python3 cameraTest.py 
2019-12-12 16:48:28,625 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:30,649 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:32,678 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:34,705 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:36,732 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:38,766 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:40,792 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:42,828 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:44,853 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:46,879 - Camera Test - DEBUG - not exits.
2019-12-12 16:48:48,905 - Camera Test - ERROR - File not found.

参考

Raspberry Pi 公式ドキュメントを日本語訳:一般的なWebカメラを使用する

http://igarashi-systems.com/sample/translation/raspberry-pi/usage/webcam.html

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です