准备阶段:
确保板卡可以连接上以太网
一个免驱动的摄像头
Pynq-z2板卡套件
将pyqn-z2板卡连接在电脑上,电源器模式启动,连接上usb摄像头:
这里博者购买的是一款免驱的usb摄像头(要支持uvc模式)。
串口通信:
连接完成后,在pc端打开设备管理器,查看端口号博者的是com7,putty选中串口通信,speed:115200,在open终端界面。
在终端界面登入pynq后,输入: ls /dev/video*
查看板卡是否识别到usb摄像头。
在终端界面输入命令行:
sudo apt update
sudo apt upgrade
确保包管理器是最新的,再输入命令行,安装gstreamer基础包:
sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly
这里博者的pynq镜像是pynq3.0.0,如果输入这段命令行后有报错,可以把所使用的版本号告诉gpt,让gpt查找相应的gstreamer版本包。
到这里应该就完成了板卡上环境的配置。(如果还少什么包,就按照报错的提示,让gpt写相应的命令行。)
Jupyter notebook(sever端的代码):
在usb摄像头调用上,我们使用socket库,它提供了一种在不同计算机进程间进行数据传输的机制。在互联网编程中,socket 是应用层与传输层(如 TCP/IP 协议栈)之间的接口,允许应用程序发送或接收数据,就像使用文件一样简单。简单来说就是实现网络通信,调用网络摄像头。
打开pynq-z2板卡的jupyter notebook界面,
创建一个新的.ipynb文件,命名为sever.ipynb就是服务端的代码。
import socket
import threading
import struct
import time
import cv2
import numpy
class Carame_Accept_Object:
def __init__(self, S_addr_port=("", 1100)):
self.resolution = (640, 480) # 分辨率
self.img_fps = 15 # 每秒传输多少帧数
self.addr_port = S_addr_port
self.Set_Socket(self.addr_port)
def Set_Socket(self, S_addr_port):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 端口可复用
self.server.bind(S_addr_port)
self.server.listen(5)
def check_option(object, client):
info = struct.unpack('lhh', client.recv(8))
if info[0] > 888:
object.img_fps = int(info[0]) - 888 # 获取帧数
object.resolution = list(object.resolution)
object.resolution[0] = info[1]
object.resolution[1] = info[2]
object.resolution = tuple(object.resolution)
return 1
else:
return 0
def RT_Image(object, client, D_addr):
if (check_option(object, client) == 0):
return
camera = cv2.VideoCapture(0) # 从摄像头中获取视频
img_param = [int(cv2.IMWRITE_JPEG_QUALITY), object.img_fps] # 设置传送图像格式、帧数
while (1):
time.sleep(0.1) # 推迟线程运行0.1s
_, object.img = camera.read() # 读取视频每一帧
object.img = cv2.resize(object.img, object.resolution) # 按要求调整图像大小(resolution必须为元组)
_, img_encode = cv2.imencode('.jpg', object.img, img_param) # 按格式生成图片
img_code = numpy.array(img_encode) # 转换成矩阵
object.img_data = img_code.tobytes() # 生成相应的字节数据
try:
# 按照相应的格式进行打包发送图片
client.send(
struct.pack("lhh", len(object.img_data), object.resolution[0], object.resolution[1]) + object.img_data)
except:
camera.release() # 释放资源
return
if __name__ == '__main__':
camera = Carame_Accept_Object()
while (1):
client, D_addr = camera.server.accept()
clientThread = threading.Thread(None, target=RT_Image, args=(camera, client, D_addr,))
clientThread.start()
将代码直接在jupyter上运行。
主机端代码:
在连接板卡的电脑上,用pycharm创建一个client.py
import socket
import cv2
import threading
import struct
import numpy
class Camera_Connect_Object:
def __init__(self, D_addr_port=["", 1100]):
self.resolution = [384, 288]
self.addr_port = D_addr_port
self.src = 888 + 15 # 双方确定传输帧数,(888)为校验值
self.interval = 0 # 图片播放时间间隔
self.img_fps = 15 # 每秒传输多少帧数
def Set_socket(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
def Socket_Connect(self):
self.Set_socket()
self.client.connect(self.addr_port)
print("IP is %s:%d" % (self.addr_port[0], self.addr_port[1]))
def RT_Image(self):
# 按照格式打包发送帧数和分辨率
self.name = self.addr_port[0] + " Camera"
self.client.send(struct.pack("lhh", self.src, self.resolution[0], self.resolution[1]))
while (1):
info = struct.unpack("lhh", self.client.recv(8))
buf_size = info[0] # 获取读的图片总长度
if buf_size:
try:
self.buf = b"" # 代表bytes类型
temp_buf = self.buf
while (buf_size): # 读取每一张图片的长度
temp_buf = self.client.recv(buf_size)
buf_size -= len(temp_buf)
self.buf += temp_buf # 获取图片
data = numpy.frombuffer(self.buf, dtype='uint8') # 按uint8转换为图像矩阵
self.image = cv2.imdecode(data, 1) # 图像解码
cv2.imshow(self.name, self.image) # 展示图片
except Exception as e:
print("Error:", e)
finally:
if (cv2.waitKey(10) == 27): # 每10ms刷新一次图片,按‘ESC’(27)退出
self.client.close()
cv2.destroyAllWindows()
break
def Get_Data(self, interval):
showThread = threading.Thread(target=self.RT_Image)
showThread.start()
if __name__ == '__main__':
camera = Camera_Connect_Object()
camera.addr_port[0] = input("Please input IP:")
camera.addr_port = tuple(camera.addr_port)
camera.Socket_Connect()
camera.Get_Data(camera.interval)
保存然后运行,就出现一下界面
输入你板卡的IP地址就可以正常接收摄像头传过来的视频数据。
如果遇到串口已被占用,就换一个串口号就行。