Raspberry Pi3 Model B と Webカメラで遠隔撮影
家にRaspberry PiとWebカメラが転がっていたので、大学の自由課題として作ってみました。
Linux系のOS使用したことがある人であれば、誰でも作れるような記事にする予定です。
初心者の人でもググりながらであれば、普通につくれると思います!
使用したもの
-
Raspberry Pi 3 Model B
もしこれから買うのであれば、3 Model B+や4を買ったほうがいいかと思います!
BはWi-Fiの5GHzに非対応なので、作業効率が結構悪かったです... -
Logicool Webカメラ C525
なんか中途半端な性能のWebカメラ...
価格重視なら低価格なC270、性能重視なら...C910とかがおススメ? -
Slack
IT企業御用達のチャットツールです!
今回はこのチャットツールで指示を出し、遠隔撮影させます。
アカウントの作成は事前に済ませておいてくださいね! -
備品
マウス、キーボード、モニター、電源ケーブル、HDMIケーブル、PC、MicroSDカード...など
これらはRaspberry Piを使用するのに必要です。
下準備
以下の記事を参考に、Raspberry PiにNOOBSをインストール。
第56回「改めましてラズベリーパイの基本!(1) Raspberry Pi NOOBSインストール 2017年度版」
次に、プログラムを記述するためのエディターのインストール。
ラズベリーパイを使ってみる – 歴史あるエディタ emacs をインストールする –
端末にこれを打ち込みます。
$ sudo apt-get install emacs
各自お好みのテキストエディタを入れてください!
vimとか聞いたことないよ!って人は、emacsが無難かと思います。
ただ多少の癖はあります...
Emacsの使い方
python3にslackbotライブラリをインストール
$ sudo apt-get install python3-pip
$ sudo pip3 install slackbot
$ sudo apt-get install python3-opencv
ダウンロード成功!的な表示があれば大丈夫です。
もし、あとでうまくいかなかった場合、
$ sudo apt-get install slacker
も入れてみてください。
slackbotの設定
slackbotを動かすにあたって、以下のようなディレクトリ構造にします。
- slack
- run.py
- slackbot_settings.py
- plugins
- __init__.py
- take_picture.py
slackとpluginsはディレクトリになっています。
まず、ディレクトリを作ります。今回は、ホームディレクトリ直下に作成します。
$ cd ~/
$ mkdir slack
$ cd slack/
$ mkdir plugins
これで完成しました。次に、必要なPythonプログラムを作成します。
$ touch run.py slackbot_settings.py
$ cd plugins/
$ touch __init__.py take_picture.py
これで空のPythonファイルが作成できました!
これ以降はディレクトリ移動の記述をしないので、ここまでの作業で「cdって何??」と感じた人は、以下の記事を参考にしてください。
cdコマンド——ディレクトリの移動
Pythonプログラムの作成
まず、run.pyを仕上げます。slackディレクトリへ移動し、
$ emacs run.py &
そして、出てきたエディタに以下を記述。
from slackbot.bot import Bot
def main():
bot = Bot()
bot.run()
if __name__ == '__main__':
printf('launch slackbot')
main()
同様にslackbot_settings.pyも作成します。
$ emacs slackbot_settings.py &
API_TOKEN = "xoxv-156423218-651873211325-Asf44a4ds5f45AS552" #参考例です。各自で取得したトークン値を入力してください。
DEFAULT_REPLY = "わかりませーん..."
PLUGINS = ['plugins']
なお、Botの取得&トークンの作成は、以下のページを参考にしました。
PythonによるSlack bot作成
slackのbotを作る 入門編
Raspberry Piでslackbotを飼う
そして、pluginsディレクトリに移動し、take_picture.pyを作成します。
from slackbot.bot import respond_to
from slackbot.bot import listen_to
from slackbot.bot import default_reply
from slacker import Slacker
import os
import cv2
import time
@respond_to('写真')
def picture_func(message):
message.reply('撮影中...')
#take_picture
cap = cv2.VideoCapture(0)
cap.read()
time.sleep(1)
ret, frame = cap.read()
cv2.imwrite("/home/pi/slack/plugins/picture.jpg",frame)
time.sleep(2)
cap.release()
time.sleep(2)
#upload_picture
TOKEN = "xoxv-156423218-651873211325-Asf44a4ds5f45AS552"
#先ほどのトークンと同じものを記述
CHANNEL = "APODV2HW1"
#取得方法は後述
file = "/home/pi/slack/plugins/picture.jpg"
filename = 'webcam'
message.reply('撮影完了...!')
time.sleep(1)
slacker = Slacker(TOKEN)
slacker.files.upload(file_=file, channels=CHANNEL)
CHANNELの値は、PCでslackを開いたときのリンクの__' '__で囲まれた部分です。私は#generalのCHANNEL値を取得しました。
https://app.slack.com/client/MQ18ALEJ/'APODV2HW1'/files
#実行方法
slackディレクトリに移動し、
python3 run.py
を実行するだけです。そして、slackで以下のように指示すると写真が撮れます。
ちなみに、raspbotは自作Botの名前です。そしてiPhoneから命令出してます。早朝の真っ暗な部屋でモニターを撮影させています。
#解説
###run.py
実行プログラムです。このプログラムを実行すると、自作したBotが実行されます。
$ python3 run.py
###slackbot_settings.py
自作したBotが必要とするデータを格納しておくプログラムです。
-
API_TOKEN
自作したBotの識別値 -
DEFAULT_REPLY
このBot宛てのメッセージで、定義していない言葉が送られてきたときの反応 -
PLUGINS
自作Botの機能拡張を行うプログラムの保存場所。この例では、~/slack/plugins/ディレクトリ内にあるプログラムも、run.pyの実行と同時に実行されます。
###__init__.py
中身は空のプログラムです。
###take_picture.py
ここで、自作Bot宛てに送られてきたメッセージ内容の判定、写真の撮影、slack上にアップロードのすべての処理を行っています。
-
@respond_to(' ')
' '内に囲まれた言葉(この例だと'写真')が送られてきた場合、以下に記述した処理(写真の撮影とアップロード)を行う。
-time.sleep(1)
()内に入れた秒数だけ次の処理の開始を遅らせる。少数も代入可能。
-
cap = cv2.VideoCapture(0)
webカメラの割り当てを行う。()内に入れた数値で、どのカメラを使用するか決める。
なお、1つしかカメラが接続されていない場合は0または-1を代入する必要がある。 -
ret, frame = cap.read()
retにはTrue / False、frameには画像データが返される。 -
cv2.imwrite("/home/pi/slack/plugins/picture.jpg",frame)
画像を指定した名前で指定したディレクトリに保存する。 -
cap.release()
カメラの解放。 -
slacker.files.upload(file_=file, channels=CHANNEL)
Slacker(TOKEN).files.upload(file_="/home/pi/slack/plugins/picture.jpg"
, channels=CHANNEL)ということ。
要するに画像アップロード処理。
#補足説明
試行錯誤しながら作成したので、不要な部分が結構ありそうですが、多めに見てください...
###__init__.py
このプログラムが置かれているディレクトリはパッケージとして扱われるそうです。あと、ここに初期化処理を記述することもできます。
なお、Python3.3以降ではこれが無くても、パッケージとして認識するそうなので、おそらく作成しなくても実行できると思いますが...慣習的なものなので作成しました。
###' 'と" "の違い
Pythonにおいて、違いはありません。ごちゃ混ぜになってますが問題はありません。
###take_picture部分の処理
cap = cv2.VideoCapture(0)
cap.read()
time.sleep(1)
ret, frame = cap.read()
この部分では、1枚目の写真を撮った後1秒待ち、2枚目の写真を撮影し保存しています。このような処理をしている理由ですが、どこかでLogicoolのカメラはこのようにしたほうが良い、というような記事を見たからです。(どこのページだったか忘れたのでリンクはありません...ごめんなさいm(_ _)m)
そこで、実際に比較実験をしたところ、C525では目に見える差がありませんでした。よって気分でこの方法を使用しています。
もし、1秒でも短縮したい場合は、
cap = cv2.VideoCapture(0)
#cap.read()
#time.sleep(1)
ret, frame = cap.read()
このようにコメントアウトでもしてください。
###slackerについて
当初、画像アップロード処理中にエラーが多発していました。
requests.post(url = 'https://~~~ ',params = param, files = file)
で画像アップロード処理を行っていたんですが、デバッグをしたところ、この関数がうまく機能していなかったので、slackerでアップロード処理を行いました。ただし、requests.post()のほうが一般的っぽいです。
###ipアドレスの固定化問題
sshログイン環境を整えるため、Raspberry Piのプライベートipアドレスを固定したところ、slackへの接続ができなくなってしまいました...slack側で設定をいじれば繋がる可能性がありますが、残念ながらslackに詳しくないため、ipアドレスの固定化を断念して使っています。
#最後に
長文にお付き合いいただき、ありがとうございました!
おそらくこれで作れると思いますが、もし何かミスがあったらご指摘お願いします...!