树莓派4学习记录(4)-摄像头

树莓派摄像头的玩法

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传输拥塞,导致视频卡顿,甚至卡死。建议结合实际的视频大小和设置的缓冲区大小,综合考量。

  • 4
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值