树莓派摄像头的玩法
1. 使能摄像头外设
依旧是:
sudo raspi-config
选择5 interfacing options:
选择P1 camera:
选择yes:
使能摄像头结束。
2. 简单拍照
直接上代码:
raspistill -o new.jpg
等待几秒钟,然后保存一个图片到当前目录
详细的参数可以参考:
raspistill 详细参数设置
3. http + vlc获取视频流
3.1 服务器端(树莓派)
直接上命令:
sudo raspivid -o - -rot 180 -t 0 -w 640 -h 480 -fps 30|cvlc -vvv stream:///dev/stdin --sout '#standard{access=http,mux=ts,dst=:8090}' :demux=h264
-rot: 图像旋转180(我添加了这个,自己看情况是否添加);
-t:延时
-w:输出视频宽度
-h:输出视频高度
-fps:输出视频帧数
access:http协议传输
dst:目标端口(输出端口)
demux:编码格式
3.2 本地
使用vlc打开网络串流:
播放即可。
目前发现的问题:延迟很高,并且会掉帧。
4. opencv获取视频并播放
4.1 安装opencv
因为我使用的是树莓派自带的python3.7环境,所以我可以直接从官方库源中安装:
sudo apt-get install python3-opencv
十分简单
4.2 使用opencv获取视频流并播放出来
直接先上脚本,具体工作原理看注释:
# coding: utf-8
import cv2
import picamera
import picamera.array
import numpy as np
import time
from fractions import Fraction
# 构建一个相机对象
with picamera.PiCamera() as camera:
camera.start_preview()
camera.rotation = 180 # 旋转180度
camera.resolution = (320, 240)# 画幅大小
# camera.saturation = 60 # 饱和度
# camera.brightness = 60 # 亮度(50表示白平衡的状态)
# camera.shutter_speed = 600 # 相机快门速度
camera.iso = 1000
camera.framerate = 32
camera.hflip = False # 是否进行水平翻转
camera.vflip = False #是否进行垂直翻转
# 摄像头预热
time.sleep(1)
# 构建一个相机的输出流对象
with picamera.array.PiRGBArray(camera) as stream:
while True:
# 抓取流,以端口的形式获取
camera.capture(stream, 'bgr', use_video_port=True)
# 以帧的形式,逐帧显示
cv2.imshow('fram', stream.array)
# 使用opencv解码numpy
data = np.fromstring(stream.getvalue(), dtype=np.uint8)
img = cv2.imdecode(data, 1)
# 等待结束指令
if cv2.waitKey(1) & 0xFF == ord('q'):
break
stream.seek(0)
stream.truncate()
cv2.destroyAllWindows()
效果:
5. opencv + UDP传输
当然是用UDP传输,肯定首先要设置服务器端(server)和客户端(client),这里我的交互设置是这样的:
服务器端:树莓派
客户端:本地PC
交互逻辑:树莓派等待PC访问(阻塞等待),如果有连接请求,则与之建立UDP连接,传输视频流数据。
直接上代码:
服务器端(server.py):
# coding: utf-8
import cv2
import numpy
import socket
import struct
# 建立套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定树莓派IP,用户任意定制端口
s.bind(("192.168.1.6", 6000))
print("UDP bound on port 6000...")
print('now starting to send frames...')
# opencv创建视频抓取对象
capture=cv2.VideoCapture(0)
# 阻塞等待客户端访问请求
data, addr = s.recvfrom(1024)
# 设置分辨率
capture.set(3, 256)
capture.set(4, 256)
# 主循环
while True:
# 以下三行尝试读取视频流(帧)
success,frame=capture.read()
while not success and frame is None:
success,frame=capture.read() #获取视频帧
# opencv对获得到的视频编码
result,imgencode=cv2.imencode('.jpg',frame,[cv2.IMWRITE_JPEG_QUALITY,50])
# 发送数据(视频)大小
s.sendto(struct.pack('i',imgencode.shape[0]), addr)
# 发送数据
s.sendto(imgencode, addr)
s.close()
客户端(client.py):
# coding: utf-8
import cv2
import numpy
import socket
import struct
# 建立套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 服务器IP与端口
addr = ("192.168.1.6", 6000)
# 建立初始化连接
data = 'hello'
s.sendto(data.encode(), addr)
print('now waiting for frames...')
# 主循环
while True:
# 接收数据,缓冲区大小(65536)
data, addr = s.recvfrom(65535)
# 如果服务器停止发送数据,则退出程序
if len(data)==1 and data[0]==1: #如果收到关闭消息则停止程序
s.close()
cv2.destroyAllWindows()
exit()
# 校验数据设置(接收服务器发送的校验信息(数据长度))
if len(data)!=4: #进行简单的校验,长度值是int类型,占四个字节
length=0
else:
length=struct.unpack('i',data)[0] #长度值
# 继续接收数据主体
data,address=s.recvfrom(65535)
# 如果此次接收到的数据长度与校验长度不同,直接进入下次接收
if length!=len(data):
continue
data=numpy.array(bytearray(data)) #格式转换
imgdecode=cv2.imdecode(data,1) #解码
cv2.imshow('frames', imgdecode) #窗口显示
if cv2.waitKey(1)==27: #按下“ESC”退出
break
# 关闭套接字
s.close()
cv2.destroyAllWindows()
值得注意的是:
如果视频过大,会导致UDP传输拥塞,导致视频卡顿,甚至卡死。建议结合实际的视频大小和设置的缓冲区大小,综合考量。
转载:https://blog.csdn.net/qq_35044509/article/details/105583582
查看评论