Web 界面较硬核,可自行魔改

原作者为 Marcelo Rovai · Github

环境

硬件

  • Raspberry 3
    • 之后的版本都可以
  • 树莓派 CSI 接口的摄像头
  • 显示器
    • 可选,我这里接了官方七寸 LCD 屏

软件

  • Raspbian Buster
  • python 3.7.7
    • flask
    • 这两个 buster 自带,应该不用手动安装

参考

步骤

  1. 安装摄像头(详见 简易树莓派拍照远程监控,为了方便阅读复读一次)
    • 排线蓝色一面朝向以太网接口,插反不会 boom 但无法识别
    • 不能热插拔
    • 摄像头板子上有 led 灯(拍照的时候会亮),注意不要用导电的材料连通,否则灯会坏(反而更隐蔽?),我当时为了省事把摄像头卡在两根 GPIO 针中间,某天碰了一下,一个火花闪过LED再也没亮过
  2. 测试摄像头
    • 执行指令,拍张照先
      raspistill -o ~/Desktop/image.jpg


      这块没被打码的湿巾桶会作为之后成功运行的证据

  3. 建立 flask 项目结构
    • 新建 static 目录(flask 会从该目录加载样式表和 js)
    • 在 static 目录新建样式表 style.css
      body{
          background: blue;
          color: yellow;
          padding:1%;
          text-align: center;
      }

      想美观一点就改一下配色

    • 新建与 static 目录同级的 templates 目录(flask 会从该目录加载 html 模板)
    • 在 templates 目录下新建 index.html
      <html>
        <head>
          <title>MJRoBot Lab Live Streaming</title>
          <link rel="stylesheet" href='../static/style.css'/>
        </head>
        <body>
          <h1>MJRoBot Lab Live Streaming</h1>
          <h3><img src="{{ url_for('video_feed') }}" width="50%"></h3>
          <hr>
          <p> @2018 Developed by MJRoBot.org</p>
        </body>
      </html>
  4. flask 代码
    • 源代码在参考链接中(作者不是我),这里复读一遍
      • 注意:如果选择下载作者的代码,请使用 camWebServer 目录下的代码,camWebServer2 中添加了温湿度传感器 DHT22 的代码,如果没有连接 DHT22 会报错
    • 在 static 的同级目录下新建 app.py
      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      #
      #   appCam.py
      #   based on tutorial ==> https://blog.miguelgrinberg.com/post/video-streaming-with-flask
      #   PiCam Local Web Server with Flask
      # MJRoBot.org 19Jan18
      
      from flask import Flask, render_template, Response
      
      # Raspberry Pi camera module (requires picamera package)
      from camera_pi import Camera
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def index():
          """Video streaming home page."""
          return render_template('index.html')
      
      
      def gen(camera):
          """Video streaming generator function."""
          while True:
              frame = camera.get_frame()
              yield (b'--frame\r\n'
                     b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
      
      
      @app.route('/video_feed')
      def video_feed():
          """Video streaming route. Put this in the src attribute of an img tag."""
          return Response(gen(Camera()),
                          mimetype='multipart/x-mixed-replace; boundary=frame')
      
      
      if __name__ == '__main__':
          app.run(host='0.0.0.0', port =80, debug=True, threaded=True)
    • 在 static 的同级目录下新建 camera_pi.py
      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      #
      #  camera_pi.py
      #  
      #  
      #  
      import time
      import io
      import threading
      import picamera
      
      
      class Camera(object):
          thread = None  # background thread that reads frames from camera
          frame = None  # current frame is stored here by background thread
          last_access = 0  # time of last client access to the camera
      
          def initialize(self):
              if Camera.thread is None:
                  # start background frame thread
                  Camera.thread = threading.Thread(target=self._thread)
                  Camera.thread.start()
      
                  # wait until frames start to be available
                  while self.frame is None:
                      time.sleep(0)
      
          def get_frame(self):
              Camera.last_access = time.time()
              self.initialize()
              return self.frame
      
          @classmethod
          def _thread(cls):
              with picamera.PiCamera() as camera:
                  # camera setup
                  camera.resolution = (320, 240)
                  camera.hflip = True
                  camera.vflip = True
      
                  # let camera warm up
                  camera.start_preview()
                  time.sleep(2)
      
                  stream = io.BytesIO()
                  for foo in camera.capture_continuous(stream, 'jpeg',
                                                       use_video_port=True):
                      # store frame
                      stream.seek(0)
                      cls.frame = stream.read()
      
                      # reset stream for next frame
                      stream.seek(0)
                      stream.truncate()
      
                      # if there hasn't been any clients asking for frames in
                      # the last 10 seconds stop the thread
                      if time.time() - cls.last_access > 10:
                          break
              cls.thread = None
  5. 运行 flask
    • 执行指令
      sudo python3 app.py

      注意不是 root 用户需要 sudo,不然权限不够无法监听 Web 端口

Continue reading “树莓派 CSI 摄像头 + Flask 实现轻量 Web 直播串流”

此问题在 Catalina 相关问题解决 中出现过,现添加了执行脚本

问题描述

macOS 每次版本升级后,打开旧 app 提示

xxx.app 已损坏,无法打开。您应该将它移到废纸篓。

解决方法

方法一

参见 macOS 允许任何来源,开启设置中的【任何来源】选项,复读一遍方法:

  1. 打开 终端.app,执行指令
    sudo spctl --master-disable
  2. 进入【系统偏好设置 – 安全性与隐私】,选择【任何来源】

显然此方法并没有解决我的问题,见方法二

方法二

麻烦一点,需要每个 app 都设置一遍

  1. 打开 终端.app,执行指令
    sudo xattr -r -d com.apple.quarantine [your app path]

    其中,[your app path] 为对应应用的路径,通常在 /Application 下

为方便每次运行,编写了下面的脚本:

#! /bin/sh
if [ -z "$1" ]
then
    echo "Usage appreg [the application path (normally is /Application/xxx.app)]"
else
    sudo xattr -r -d com.apple.quarantine "$1"
fi

新建 appreg 文件(没有后缀),复制粘贴上面的代码,执行指令

sudo chmod +x [your path here]/appreg

获取执行权限,执行指令

sudo ln -s [your path here]/appreg /usr/local/bin/appreg

将脚本链接到 /usr/local/bin 下

之后在 终端.app 中执行指令

appreg /Application/xxxx.app

即可解决该 app 无法打开的问题 Continue reading “解决 Catalina xxx.app 已损坏移到废纸篓问题”