组件:

  • Raspberry Pi 3B 1G
  • RMONCAM G180摄像头

环境:

  • Python:3.7.3
  • Flask:1.0.2
  • opencv-python:4.5.3.56

一、打开相机配置

打开你的树莓派并转到树莓派配置工具的主菜单上,并确认相机接口是否开启:
如果你需要开启它,请按[Enable]并重新启动你的树莓派。

树莓派+Flask实现远程拍照WEB服务器_flask
树莓派+Flask实现远程拍照WEB服务器_前端_02
做一个简单的测试来验证一切是否正常:
以下为 CSI摄像头测试

raspistill -o /Desktop/image.png

如果使用的是USB摄像头,则在树莓派终端输入 sudo apt-get install fswebcam 安装 ​​fswebcam​​。通过输入sudo fswebcam image.jpg进行拍照测试。使用方法可以通过输入fswebcam -h查询。

安装 fswebcam

sudo apt-get install fswebcam

pi@raspberrypi:~/Desktop $ sudo apt-get install fswebcam
正在读取软件包列表… 完成
正在分析软件包的依赖关系树
正在读取状态信息… 完成
下列软件包是自动安装的并且现在不需要了:
gconf-service gconf2-common libgconf-2-4 python-colorzero
使用’sudo apt autoremove’来卸载它(它们)。
下列【新】软件包将被安装:
fswebcam
升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 3 个软件包未被升级。
需要下载 43.5 kB 的归档。
解压缩后会消耗 116 kB 的额外空间。
获取:1 http://mirrors.aliyun.com/raspbian/raspbian buster/main armhf fswebcam armhf 20140113-2 [43.5 kB]
已下载 43.5 kB,耗时 0秒 (142 kB/s)
正在选中未选择的软件包 fswebcam。
(正在读取数据库 … 系统当前共安装有 177053 个文件和目录。)
准备解压 …/fswebcam_20140113-2_armhf.deb …
正在解压 fswebcam (20140113-2) …
正在设置 fswebcam (20140113-2) …
正在处理用于 man-db (2.8.5-2) 的触发器 …

测试 USB摄像头 拍照

sudo fswebcam image.jpg

pi@raspberrypi:~/Desktop $ sudo fswebcam image.jpg
— Opening /dev/video0…
Trying source module v4l2…
/dev/video0 opened.
No input was specified, using the first.
Adjusting resolution from 384x288 to 352x288.
— Capturing frame…
Captured frame in 0.00 seconds.
— Processing captured image…
Writing JPEG image to ‘image.jpg’.
pi@raspberrypi:~/Desktop $

如果拍照成功,在到你树莓派桌面上会出现一个图像图标。 点击打开它, 如果出现图像,则说明准备步骤已经完成。如果你想获得更多关于相机的信息,可点击 ​​Getting started with picamera​​.。

fswebcam 常用参数
  • /dev/video0:指定摄像头操作设备
    通过输入以下命令可以查看可用的摄像头操作设备

ls /dev/video*

pi@raspberrypi:~/Desktop $ ls /dev/video*
/dev/video0 /dev/video10 /dev/video12 /dev/video14 /dev/video16
/dev/video1 /dev/video11 /dev/video13 /dev/video15

  • –no-banner:图片上隐藏横幅。
  • -r 640x480:设置图片分辨率 640x480,默认是352x288。
  • ./static/image.jpg:存储路径,当前用户目录下,保存为 image.jpg。

例如:

fswebcam /dev/video0 --no-banner -r 640x480 ./static/image.jpg

二、安装FLASK

创建一个Flask Web服务器环境:
首先要做的是在你的树莓派上安装Flask,去终端并输入:

sudo apt-get install python3-flask

pi@raspberrypi:~/Desktop $ sudo apt-get install python3-flask
正在读取软件包列表… 完成
正在分析软件包的依赖关系树
正在读取状态信息… 完成
python3-flask 已经是最新版 (1.0.2-3)。
下列软件包是自动安装的并且现在不需要了:
gconf-service gconf2-common libgconf-2-4 python-colorzero
使用’sudo apt autoremove’来卸载它(它们)。
升级了 0 个软件包,新安装了 0 个软件包,要卸载 0 个软件包,有 3 个软件包未被升级。

在桌面新建文件夹

mkdir camWebServer

按照上面的命令,创建一个名为“camWebServer”的文件夹,并在这里保存我们的python脚本:

以下为 camWebServer文件夹 所在的路径位置。

/home/pi/Desktop/camWebServer

在这个camWebServer文件夹里,创建两个子文件夹:静态的CSS、最终的JavaScript文件以及HTML文件的模板。 转到你的新创建的文件夹:

cd camWebServer

并创建2个新的子文件夹:

mkdir static
mkdir templates

最终的目录“树”,如下所示:

├── Desktop
├── camWebServer
├── templates
└── static

三、创建单线程视频流服务器

通过opencv 打开USB摄像头,并将摄像头拍到的画面显示在浏览器中。

安装 opencv-python 库

pip install opencv-python

app.py
from flask import Flask, render_template, Response
from camera import VideoCamera

app = Flask(__name__)

@app.route('/')
def index():
return render_template('index.html')

def gen(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

@app.route('/video_feed')
def video_feed():
return Response(gen(VideoCamera()),
mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=True)
camera.py
import cv2

class VideoCamera(object):
def __init__(self):
# Using OpenCV to capture from device 0. If you have trouble capturing
# from a webcam, comment the line below out and use a video file
# instead.
self.video = cv2.VideoCapture(0)
# If you decide to use video.mp4, you must have this file in the folder
# as the main.py.
# self.video = cv2.VideoCapture('video.mp4')

def __del__(self):
self.video.release()

def get_frame(self):
success, image = self.video.read()
# We are using Motion JPEG, but OpenCV defaults to capture raw images,
# so we must encode it into JPEG in order to correctly display the
# video stream.
ret, jpeg = cv2.imencode('.jpg', image)
# 对于 python2.7 或者低版本的 numpy 请使用 jpeg.tostring()
return jpeg.tobytes()

将index.html文件存放到templates文件夹下:

<html>
<head>
<title>视频流</title>
<link rel="stylesheet" href='../static/style.css'/>
</head>
<body>
<h3><img src="{{ url_for('video_feed') }}" width="50%"></h3>
</body>
</html>

将style.css文件存放到static文件夹下:

body{
background:&nbsp;blue;
color:&nbsp;yellow;
padding:1%;
text-align:&nbsp;center;
}

index.html最重要的一行是:

<img src="{{ url_for('video_feed') }}" width="50%">

视频将会在这里“反馈”到我们的网页上。

确保所有的文件都在正确的位置,所有数据更新后,检查一下我们的环境:

├── Desktop
├── camWebServer
├── camera_pi.py
├── app.py
├── templates
| ├── index.html
└── static
├── style.css

现在,在终端上运行python脚本:

sudo python3 app.py

转到你的网络中的任何浏览器,并输入 http://树莓派的IP地址/video_feed

效果如下:

树莓派+Flask实现远程拍照WEB服务器_ide_03

注意:如果你不能确定你的树莓派IP地址,请在你的终端上运行:

ifconfig

在wlan0:部分你会找到树莓派IP地址。

当多台电脑同时访问 http://树莓派的IP地址/video_feed 只有一个页面会显示画面,如果有需求可以加入多线程代码。

树莓派拍照服务器

通过cmd命令,实现访问拍照接口,将照片保存到项目的static文件夹中,然后通过 http://树莓派的IP地址/get_image 获取照片。

# main.py
from flask import Flask, render_template, Response, url_for, send_file
import cv2
import time

app = Flask(__name__)

@app.route(&#39;/')
def index():
return render_template(&#39;index.html')

def run_cmd( cmd_str=&#39;', echo_print=1):
"""
执行cmd命令,不显示执行过程中弹出的黑框
备注:subprocess.run()函数会将本来打印到cmd上的内容打印到python执行界面上,所以避免了出现cmd弹出框的问题
:param cmd_str: 执行的cmd命令
:return:
"""
from subprocess import run
if echo_print == 1:
print(&#39;\n执行cmd指令="{}"'.format(cmd_str))
run(cmd_str, shell=True)

@app.route(&#39;/get_image')
def get_image():
run_cmd(&#39;sudo fswebcam ./static/images/test.jpg')
#return "保存test.jpg成功!"
return send_file(&#39;./static/images/test.jpg', mimetype='image/jpg')


if __name__ == &#39;__main__':
app.run(host=&#39;0.0.0.0', port=80, debug=True)

效果如下:

树莓派+Flask实现远程拍照WEB服务器_ide_04

通过cmd命令,实现拍照,将照片保存到项目的static文件夹中,然后通过 http://树莓派的IP地址/get_image 获取照片。

test.html文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="{{url_for('static',filename='images/test.jpg',_t=val1)}}" alt="">
</body>
</html>

app.py文件

# main.py
from flask import Flask, render_template, Response, url_for, send_file
import cv2
import time

app = Flask(__name__)

@app.route(&#39;/')
def index():
return render_template(&#39;index.html')

def run_cmd( cmd_str=&#39;', echo_print=1):
"""
执行cmd命令,不显示执行过程中弹出的黑框
备注:subprocess.run()函数会将本来打印到cmd上的内容打印到python执行界面上,所以避免了出现cmd弹出框的问题
:param cmd_str: 执行的cmd命令
:return:
"""
from subprocess import run
if echo_print == 1:
print(&#39;\n执行cmd指令="{}"'.format(cmd_str))
run(cmd_str, shell=True)

@app.route(&#39;/get_image')
def get_image():
run_cmd(&#39;sudo fswebcam ./static/images/test.jpg')
#return "保存test.jpg成功!"
return render_template("test.html", val1=time.time())
#return render_template("test.html")


if __name__ == &#39;__main__':
app.run(host=&#39;0.0.0.0', port=80, debug=True)

注:在网页中图片显示不能及时更新,由于缓存的问题,拍照存储的图片覆盖原有的图片,但是前端页面刷新还是以前的旧图。需要_t参数,使每次请求的数据不一样,才能刷新图片。

出现问题:

问题:

树莓派上可以找到摄像头驱动,但是在树莓派终端输入raspistill -o image.jpg,输出如下错误:

pi@raspberrypi:~/Desktop $ raspistill -o /Desktop/image.png
mmal: Cannot read camera info, keeping the defaults for OV5647
mmal: mmal_vc_component_create: failed to create component ‘vc.ril.camera’ (1:ENOMEM)
mmal: mmal_component_create_core: could not create component ‘vc.ril.camera’ (1)
mmal: Failed to create camera component
mmal: main: Failed to create camera component
mmal: Camera is not detected. Please check carefully the camera module is installed correctly

其原因为使用的摄像头为USB摄像头,而raspistill命令只能用于CSI摄像头。对于USB接口的摄像头,可以通过调用fswebcam进行访问。

参考:​​https://shumeipai.nxez.com/2018/07/03/video-streaming-web-server-with-flask.html​