组件:
- Raspberry Pi 3B 1G
- RMONCAM G180摄像头
环境:
- Python:3.7.3
- Flask:1.0.2
- opencv-python:4.5.3.56
一、打开相机配置
打开你的树莓派并转到树莓派配置工具的主菜单上,并确认相机接口是否开启:
如果你需要开启它,请按[Enable]并重新启动你的树莓派。
做一个简单的测试来验证一切是否正常:
以下为 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__)
.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')
.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: blue;
color: yellow;
padding:1%;
text-align: 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
效果如下:
注意:如果你不能确定你的树莓派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__)
.route('/')
def index():
return render_template('index.html')
def run_cmd( cmd_str='', echo_print=1):
"""
执行cmd命令,不显示执行过程中弹出的黑框
备注:subprocess.run()函数会将本来打印到cmd上的内容打印到python执行界面上,所以避免了出现cmd弹出框的问题
:param cmd_str: 执行的cmd命令
:return:
"""
from subprocess import run
if echo_print == 1:
print('\n执行cmd指令="{}"'.format(cmd_str))
run(cmd_str, shell=True)
.route('/get_image')
def get_image():
run_cmd('sudo fswebcam ./static/images/test.jpg')
#return "保存test.jpg成功!"
return send_file('./static/images/test.jpg', mimetype='image/jpg')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=True)
效果如下:
通过cmd命令,实现拍照,将照片保存到项目的static文件夹中,然后通过 http://树莓派的IP地址/get_image 获取照片。
test.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__)
.route('/')
def index():
return render_template('index.html')
def run_cmd( cmd_str='', echo_print=1):
"""
执行cmd命令,不显示执行过程中弹出的黑框
备注:subprocess.run()函数会将本来打印到cmd上的内容打印到python执行界面上,所以避免了出现cmd弹出框的问题
:param cmd_str: 执行的cmd命令
:return:
"""
from subprocess import run
if echo_print == 1:
print('\n执行cmd指令="{}"'.format(cmd_str))
run(cmd_str, shell=True)
.route('/get_image')
def get_image():
run_cmd('sudo fswebcam ./static/images/test.jpg')
#return "保存test.jpg成功!"
return render_template("test.html", val1=time.time())
#return render_template("test.html")
if __name__ == '__main__':
app.run(host='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