板卡介绍
1、Sipeed M1s Dock 是基于 Sipeed M1s 模组来设计的一款核心板,引出了 MIPI CSI、SPI LCD 等 FPC 接口,免去接线难的烦恼。使用最精简的设计,用于客户对模组进行模组评估,或者爱好者直接上手游玩等用途。
3、板卡特点:
- 主芯片 BL808 RISC-V 480Mhz + NPU BLAI-100
- 板载 USB 转 UART 调试器(可实现一键点击烧录,无需按实体按键)
- 1.69 寸 240x280 电容触摸屏
- 200W 像素摄像头
- 支持 2.4G WIFI / BT / BLE
- 板载 1 个模拟麦克风、1 个 LED、1 个 TF 卡座
- 引出一路 USB-OTG 到 USB Type-C 接口
此次板卡还可以连接wifi,实现远程数据上传等物联网方便的任务。是一款非常适合入门学习机器学习,AI识别的开发板
任务要求
项目5 - 网络相机
目标:完成一个基于Sipeed M1s Dock 的网络相机
具体要求:
- 完成相机驱动,定时拍摄图片,并将图片通过网络传到电脑或服务器,实现长时间拍摄
- 通过电脑端编程将图片合成为一个视频
设计思路
我们将Sipeed M1s Dock设备作为下位机,其主要的作用就是连接网络并且拍摄图片,再将拍摄好的照片通过WiFi传输到指定的上位机。这里程序可通过视频讲解进行代码编译,并且下载,本次使用到的下位机程序由官方提供。
由于我的电脑对 8888端口冲突,因此本项目的端口号我改为了8889。
上位机,作为采集照片,并且将采集到的照片进行存储。
上位机采用python编程语言,编译器使用的是pycharm。
存储路径:(所存储的路径均为目录文件的相对路径,这样为了以后项目更好的移植等等)
│ ├─m1s code
│ │ │ img
│ │ │ video
│ │ │ main.py
我是用tkinter库作为上位机的界面。
我的设计思路是:
1、下位机连接WiFi,开始等待握手数据包。
2、打开上位机,连接下位机并且开始建立tcp连接,成功之后等待采集照片命令。
3、点击开始拍摄按钮,上位机开始接收下位机发来的图片,并且将图片按照顺序存储到相对路径的img文件夹内
4、点击停止拍摄并播放,这里思路采用逐次执行三个函数,第一个是停止函数,这里采用线程的方法实现开始和暂停。
然后再将img文件夹内的照片进行二次排序,通过opencv库实现图片转换成视频。紧接着在上位机上进行播放视频。
代码解释
此次上位机使用python语言来开发。实际上我将停止采集和图片合成视频以及播放写在一个函数当中,可以一键完成视频的播放,更加直观,此次项目使用了一下库:
import socket
import numpy as np
import cv2 as cv
import tkinter as tk
from tkinter import *
import os
from PIL import Image, ImageTk
import threading
from tkinter.messagebox import *
python太好用了!!!!
采集图片
首先与下位机建立TCP链接,在主程序中,通过线程设定一个标志位来实现开始和暂停。
def code_main():
global stop_flag
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
tcp_server.bind(("192.168.31.124", 8889))
tcp_server.listen(128)
tcp_client, tcp_client_address = tcp_server.accept()
# 代码执行到此说明连接建立成功
print("摄像头连接成功,IP端口号为", tcp_client_address)
index = 1
while True:
if stop_flag == 1:
# 接收客户端发送的数据, 这次接收数据的最大字节数是4
recv_data = tcp_client.recv(4)
mjpeg_len = int.from_bytes(recv_data, 'little')
# print("recv len: ", mjpeg_len)
tcp_client.send(recv_data)
recv_data_mjpeg = b''
remained_bytes = mjpeg_len
while remained_bytes > 0:
recv_data_mjpeg += tcp_client.recv(remained_bytes)
remained_bytes = mjpeg_len - len(recv_data_mjpeg)
# print("recv stream success")
if recv_data_mjpeg[:2] != b'\xff\xd8' \
or recv_data_mjpeg[-2:] != b'\xff\xd9':
continue
mjpeg_data = np.frombuffer(recv_data_mjpeg, 'uint8')
img = cv.imdecode(mjpeg_data, cv.IMREAD_COLOR)
# cv.imshow('Online Video', img)
# 保存图片
cv.imwrite(path + './img/' + str(index) + ".jpg", img)
print("已将" + str(index) + ".jpg 图片成功保存!")
index += 1
elif stop_flag == 0:
print("停止获取")
stop_flag = 1
Generate_video()
play_video()
break
转换视频
讲得到的图片先进行排序,按照文件的名称。随之通过CV库来生成视频
def Generate_video():
for root, dirs, files in os.walk(file_dir):
for file in files:
list.append(file) # 获取目录下文件名列表
list.sort(key=lambda x: int(x[:-4])) ##文件名按数字排序,不然会卡帧
# VideoWriter是cv2库提供的视频保存方法,将合成的视频保存到该路径中
# 'MJPG'意思是支持jpg格式图片
# fps = 20代表视频的帧频为5,如果图片不多,帧频最好设置的小一点
# (800,600)是生成的视频像素800*600,一般要与所使用的图片像素大小一致,否则生成的视频无法播放
# 定义保存视频目录名称和压缩格式,像素为1280*720
#生成视频 = 存放路径 + 视频格式 + 视频格式类型 + 帧率 + 视频像素
video = cv.VideoWriter(path +'./video/myvideo.avi',cv.VideoWriter_fourcc(*'MJPG'),10,(800,600))
for i in range(1, len(list)):
# 读取图片
img = cv.imread(path + './img/' + list[i - 1])
# 将图片转换为1280*720像素大小
img = cv.resize(img, (800, 600))
# 写入视频
video.write(img)
# 释放资源
print("视频生成成功" + path +'\\video\\myvideo.avi')#给个弹窗提示吧
showinfo('信息', '完成')
video.release()
播放视频
将视频通过tkinter界面显示出来
def play_video():
print("播放视频")
wait_time = 1000 / 55 #播放速度
# 刷新一下目录
while video.isOpened(): # 如果被打开
result, movieFrame = video.read() # 读取视频对象的信息 result 代表视频还有没有帧数,如果有,那么True,否则反之,第二个是帧的图片序列
if result: # 如果视频没播完
v_image = cv.cvtColor(movieFrame, cv.COLOR_BGR2RGBA)#视频色差
image_cv = Image.fromarray(v_image) # 将帧的图片序列转化为图片对象
image_tk = ImageTk.PhotoImage(image=image_cv) # 将图片对象传入tkinter支持的对象
Label_movie.config(image=image_tk) # 将Label的图片参数修改为image_tk
Label_movie.image = image_tk # 同上,如果少了这句话,那么会导致部分的视频闪烁
window.update() # 更新窗口
cv.waitKey(int(wait_time))
else: # 如果视频播完了,那么退出循环
break
软件框图
活动心得
感谢硬禾学堂的寒假一起练活动,此次使用Sipeed M1s Dock成功实现了网络相机的任务,此次收获比较多,了解了linux环境,并且通过Python来制作上位机。我从中学到很多在校期间学不到的内容,此次的任务还可以更加完善,继续努力学习。争取把这个项目做的更好。同时更期待硬禾学堂的暑期活动!