【テクテクライフ】旭山記念公園と北海道神宮

思ったより難しくありませんでした。

地下鉄円山公園駅のバスターミナルから直通のバスが走ってました。

回収完了。

なかなか景色が良いです。

ちなみに、北海道神宮(円山公園内)もチェックポイントがあったので、ついでに回収しました。

リスがおりました。

【ラズパイ】【カメラ】プレビュー画面をラズパイから取得・表示

前回は、Webページをローカルで作成して、そこからブラウザに表示させていたのですが、

今回はWebページをラズパイに設置して、ブラウザからラズパイにアクセスすることによってプレビュー画面を表示させたいと思います。

動作はURLのパスによって変えます。

パスが”/”ならば、Webページを、”/Streaming”ならカメラの画像を返すようにします。

まず、Pythonのコードはこうなりました。

import base64
import cv2
import json
import os
import sys
import time
import threading

from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer
from http import HTTPStatus
from urllib.parse import urlparse

PORT = 8000

cap = cv2.VideoCapture(0)

def __main__():
    thread = threading.Thread(target=httpServe)
    thread.start()
    
    try:
        while cap.isOpened():
            time.sleep(1)
    except KeyboardInterrupt:
        return

def httpServe():
    handler = StubHttpRequestHandler
    httpd = HTTPServer(('',PORT),handler)
    httpd.serve_forever()

class StubHttpRequestHandler(BaseHTTPRequestHandler):
    server_version = "HTTP Stub/0.1"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_GET(self):
        parsed = urlparse(self.path)
        if parsed.path == '/Streaming':
            enc = sys.getfilesystemencoding()

            _, img = cap.read()
            resized_img = cv2.resize(img, (480, 320))
            _, encoded_img = cv2.imencode('.jpg', resized_img, [int(cv2.IMWRITE_JPEG_QUALITY), 30])
            dst_base64 = base64.b64encode(encoded_img).decode('utf-8')

            data = {
                'image': 'data:image/jpg;base64,' + dst_base64
            }

            encoded = json.dumps(data).encode()

            self.send_response(HTTPStatus.OK)
            self.send_header("Content-type", "text/html; charset=%s" % enc)
            self.send_header("Access-Control-Allow-Origin", "null")
            self.send_header("Content-Length", str(len(encoded)))
            self.end_headers()

            self.wfile.write(encoded)
        elif parsed.path == '/vue.min.js':
            self.send_response(HTTPStatus.OK)
            with open('vue.min.js',mode='br') as f:
                data = f.read()
            self.send_header("Content-type", "text/javascript")
            self.end_headers()
            self.wfile.write(bytes(data))
        elif parsed.path == '/jquery-3.5.1.slim.min.js':
            self.send_response(HTTPStatus.OK)
            with open('jquery-3.5.1.slim.min.js',mode='br') as f:
                data = f.read()
            self.send_header("Content-type", "text/javascript")
            self.end_headers()
            self.wfile.write(bytes(data))
        else:
            self.send_response(HTTPStatus.OK)
            with open('index.html',mode='br') as f:
                data = f.read()
            self.send_header("Content-type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(bytes(data))

__main__()

無駄にでかくなった気がする。

というのも、使用しているjsファイルもラズパイからGETしようとブラウザが動くので、jsファイルを送るように作成しないといけないのです。

めんどくさいから、他のライブラリを使用することも考えないといかんなぁ。

続いて、html側。

こちらはそんなに難しくはない。

URLを変えるだけなので。

<!DOCTYPE html>
<html>
<head>
  <title>My first Vue app</title>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script src="vue.min.js"></script>
  <script src="jquery-3.5.1.slim.min.js"></script>
</head>
<body>
  <div id="app">
      <image id="camera" src="" />
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        timer: null,
      },
      created: function() {
        self = this;
        this.timer = setInterval(function() {self.onLoad()}, 50)
      },
      methods: {
        onLoad: function() {
            axios.get('http://pi4.local:8000/Streaming').then(function(response){
                $("#camera").attr('src', response.data.image);
            }).catch(function(error){
            });
        }
      }
    })
  </script>
</body>
</html>

これで動作しました。