websocketでRaspberryPiからwindowsPCに画像を送る(Python)
Raspberypi3から webscketで画像をあげて、PC側で取得・表示までやります。
概要図↓
実行画面↓
開発環境
- win10 64bit
python3.5.2
openCV3.1.0
- Raspberrypi3
Raspbian Debian Stretch - Version:September 2017
python3.5.2
RaspberryPi側開発
構成
Raspberry Piのカメラモジュールで撮った映像をWebSocketでブラウザに送る!! - ami_GS's diary
ラズパイの方は、ほぼ上記参考HPのまま使っています。
今回は自分の環境でエラーが出たところを修正しました。
また、IP固定はあらかじめしておいてください。
ーーここ引用ーー
camera.py
RPi側でブラウザからのアクセスを受け付けるwebサーバ、及びカメラから映像を撮り、ブラウザへ送る。
index.html
WebSocketでブラウザに送られてきた画像を表示する。
ーーーーーーーー
インストール
pip3 install websocket pip3 install tornado
camera.py
import time import picamera import io import tornado import tornado.httpserver import tornado.websocket import tornado.ioloop import tornado.web import socket from threading import Thread WIDTH = 480 HEIGHT = 360 FPS = 30 class HttpHandler(tornado.web.RequestHandler): def initialize(self): pass def get(self): self.render("./index.html") #最初のHTTPアクセスを受け付け、WebSocket接続を確立させるスクリプトが入ったindex.htmlを返す class WSHandler(tornado.websocket.WebSocketHandler): def initialize(self, camera): self.camera = camera self.state = True def open(self): print(self.request.remote_ip, ": connection opened") t = Thread(target=self.loop) #撮影&送信スレッドの作成 t.setDaemon(True) t.start() def loop(self): stream = io.BytesIO() for foo in self.camera.capture_continuous(stream, "jpeg"): stream.seek(0) self.write_message(stream.read(), binary=True) stream.seek(0) stream.truncate() if not self.state: break def on_close(self): self.state = False #映像送信のループを終了させる self.close() #WebSocketセッションを閉じる print(self.request.remote_ip, ": connection closed") def piCamera(): camera = picamera.PiCamera() camera.resolution = (WIDTH, HEIGHT) camera.framerate = FPS camera.start_preview() time.sleep(2) #カメラ初期化 return camera def main(): camera = piCamera() print("complete initialization") app = tornado.web.Application([ (r"/", HttpHandler), #最初のアクセスを受け付けるHTTPハンドラ (r"/camera", WSHandler, dict(camera=camera)), #WebSocket接続を待ち受けるハンドラ ]) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8080) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
index.html
<html> <head> <title>livecamera</title> <img id="liveImg" src="" width="480" height="360"> <script type="text/javascript"> var img = document.getElementById("liveImg"); var arrayBuffer; //WebSocketでサーバに接続 var ws = new WebSocket("ws://192.168.1.201:8080/camera"); ws.binaryType = 'arraybuffer'; //受診するデータがバイナリであるので設定 ws.onopen = function(){console.log("connection was established");}; //接続が確立した時に呼ばれる ws.onmessage = function(evt){ arrayBuffer = evt.data; //受信したデータを復号しbase64でエンコード img.src = "data:image/jpeg;base64," + encode(new Uint8Array(arrayBuffer)); }; window.onbeforeunload = function(){ //ウィンドウ(タブ)を閉じたらサーバにセッションの終了を知らせる ws.close(1000); }; function encode (input) { var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; while (i < input.length) { chr1 = input[i++]; chr2 = i < input.length ? input[i++] : Number.NaN; // Not sure if the index chr3 = i < input.length ? input[i++] : Number.NaN; // checks are needed here enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output += keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); } return output; } </script> </head> </html>
*WebSocketでサーバに接続する部分のIPアドレスを自分のラズパイのIPに書き換えてください
起動
上の2つのプログラムを同じフォルダに置いて実行します。
python camera.py
ブラウザでwindowsPCからラズパイIPにアクセスするとリアルタイム画像が表示されます。
Windows側開発
構成
client.py
websocketのクライアント文とOpenCVでの画像表示になります。
インストール
pip3 install websocket-client
client.py
#-*- coding:utf-8 -*- from websocket import create_connection import sys import base64 from io import BytesIO import cv2 import numpy as np ws = create_connection("ws://192.168.1.201:8080/camera") # decode while True: arr = np.asarray(bytearray(ws.recv()), dtype=np.uint8) img = cv2.imdecode(arr, -1) # 'load it as it is' cv2.imshow('image', img) cv2.waitKey(10) cv2.destroyAllWindows() ws.close()
*create_connectionのアドレスをラズパイのアドレスに書き換えてください
起動
こっちを起動する前にラズパイの方を起動させておいてください。
ラズパイ起動確認後、以下で実行
python client.py
ウインドウが表示され、ラズパイが取得している画像が表示されます
初めてwebsocketやりました。
おわり
[参考]
Raspberry Piのカメラモジュールで撮った映像をWebSocketでブラウザに送る!! - ami_GS's diary
【技術】pythonでwebsocketを試してみた - エンジニアリングとお金の話
PicameraによるRaspberry Pi 3カメラモジュールのカメラ設定 | TomoSoft
Pythonの画像読み込み: PIL, OpenCV, scikit-image - Qiita