内容介绍
内容介绍
2023小脚丫寒假一起练项目三
项目需求
- 目标:完成一个基于Sipeed M1s Dock 的网络相机
- 具体要求:完成相机驱动,定时拍摄图片,并将图片通过网络传到电脑或服务器,实现长时间拍摄通过电脑端编程将图片合成为一个视频
结果展示
- 
烧录附件中的固件 firmware.bin,再烧录附件中的camera_streaming_through_wifi.bin,M1s Dock驱动相机进行拍摄,之后将图片通过tcp连接传输至上位机,之后上位机会将图片合成为视频

- 烧录附件中的固件firmware_delay1000.bin,再重新烧录附件中的camera_streaming_through_wifi.bin,发现现在相机每1秒拍摄一次
- 
按q结束拍摄,或者录制30s(最长录制时间可通过修改python代码的全局变量 RECORD_TIME进行设置)后自动结束。结束后会显示推荐帧率(因为受网络影响,图片传输的速率会有不同),需将python代码中的全局变量FPS修改为推荐帧率

设计思路
- 烧录例程,发现没反应,通过串口打印的调试信息,发现停在Socket connect..
- 全局搜索Socket connect..,发现在SDKcomponents\sipeed\e907\m1s_e907_xram\srcm1s_e907_xram_wifi.c的upload_stream_task
- 阅读该函数发现开发者失误将IP与端口写死,修改代码为自己要设的IP与端口,重新烧录固件,发现可以正常通信。(之后官方对代码也进行了修复,修复了此bug)
- 继续阅读代码,发现会先发送4字节的图片长度,收到回复后发送图片,之后重新获取相机拍摄图片,重复上述内容
- 根据此逻辑编写python代码接收图片并拼接为视频
代码实现
python部分
1.1 全局变量
SAVE_PATH = "D:/vedio_test/" # 视频保存地址
RECORD_TIME = 30             # 视频最大录制时间
FPS = 9                      # 视频帧率
2.1 确认发送的图片长度的格式是否正确
def check_length(length_byte):
    if length_byte[-2:] != b'\x00\x00' and len(length_byte) != 4:
        return -1
    return 02.2 接收图片
def socket_receive(conn, length_require):
    content = conn.recv(length_require)
    rev_len = len(content)
    while rev_len != length_require:
        content += conn.recv(length_require - rev_len)
        rev_len = len(content)
    # print(f"receive length: {rev_len}")
    return content3.1 视频录制相关:
class Video(threading.Thread):
    def __init__(self, save_dir: str, img_size: tuple, fps: int):
        threading.Thread.__init__(self)
        self.now_time = None
        self.flag = None
        self.start_time = None
        self.screen_file_path = None
        self.record_time = RECORD_TIME
        self.fps = fps # 帧率为25,可以调节
        self.save_dir = save_dir
        self.get_video_path()
        self.video = cv2.VideoWriter(self.screen_file_path, cv2.VideoWriter_fourcc(*'MJPG'), self.fps,
                                     img_size)
    def start_record(self):
        self.start_time = time.time()
        # 最长录制时间
    def video_record(self, img):
        self.video.write(img)
        self.now_time = time.time()
        delay = self.now_time - self.start_time
        if delay >= self.record_time:
            print("---超过指定时间,录制结束!---")
            return 0
        return 1
    def stop_record(self):
        self.video.release()
        cv2.destroyAllWindows()
    def get_video_path(self):
        # 录屏保存的文件目录路径
        if not os.path.exists(self.save_dir):
            os.makedirs(self.save_dir)
        # 得到录屏保存的文件路径 按照时间创建文件夹
        file_name = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S') + '_screen.avi'
        # 文件路径
        self.screen_file_path = os.path.join(self.save_dir, file_name)
    # 找到合适的帧率
    def get_fps(self):
        video = VideoCapture(self.screen_file_path)
        old_fps = video.get(CAP_PROP_FPS)
        Count = video.get(CAP_PROP_FRAME_COUNT)
        size = (int(video.get(CAP_PROP_FRAME_WIDTH)), int(video.get(CAP_PROP_FRAME_HEIGHT)))
        if old_fps == 0 or self.now_time == self.start_time:
            print("录制时间过短")
            return -1
        print("=========================")
        print('视频帧率=%.1f' % old_fps)
        print('视频的帧数=%.1f' % Count)
        print('视频的分辨率', size)
        print('视频时间=%.3f秒' % (int(Count) / old_fps))
        print('视频的录制时间=%.3f秒' % (self.now_time - self.start_time))
        new_fps = int(Count) / (self.now_time - self.start_time)
        print('推荐帧率=%.2f' % (new_fps))
        return 03.2 计算推荐帧率:
    def get_fps(self):
        video = VideoCapture(self.screen_file_path)
        old_fps = video.get(CAP_PROP_FPS)
        Count = video.get(CAP_PROP_FRAME_COUNT)
        size = (int(video.get(CAP_PROP_FRAME_WIDTH)), int(video.get(CAP_PROP_FRAME_HEIGHT)))
        if old_fps == 0 or self.now_time == self.start_time:
            print("录制时间过短")
            return -1
        print("=========================")
        print('视频帧率=%.1f' % old_fps)
        print('视频的帧数=%.1f' % Count)
        print('视频的分辨率', size)
        print('视频时间=%.3f秒' % (int(Count) / old_fps))
        print('视频的录制时间=%.3f秒' % (self.now_time - self.start_time))
        new_fps = int(Count) / (self.now_time - self.start_time)
        print('推荐帧率=%.2f' % (new_fps))
        return 04 主函数
4.1 建立socket连接
    s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None)
    s.bind(('192.168.89.82', 8888))
    s.listen(5)  # 等待客户端连接
    conn, addr = s.accept()  # 建立客户端连接
    print(f"connected to {addr}")4.2 获取图片长度并回复
            length_byte = socket_receive(conn, 4)
            # print(f"length_byte: {length_byte}")
            # 确认length的格式是否正确
            if check_length(length_byte) != 0:
                continue
            length = struct.unpack('i', length_byte)[0]
            # print(f"image length: {length}")
            # print("--------------------------")4.3 录制视频
            img_b = socket_receive(conn, length)
            img = cv2.imdecode(np.frombuffer(img_b, np.uint8), cv2.IMREAD_COLOR)
            cv2.imshow('test', img)
            key = cv2.waitKey(25)
            ret = video.video_record(img)
            if key == ord('q') or ret == 0:
                video.flag = True
                video.stop_record()
                video.get_fps()
                breakC语言部分
驱动1相机并通过wifi发送图片
    bl_cam_mipi_mjpeg_init();
    m1s_xram_wifi_init();
    m1s_xram_wifi_connect("xxx", "xxx");
    m1s_xram_wifi_upload_stream("x.x.x.x", 8888); 根据要求要定时拍摄,而原本代码是连续拍摄,可以在每次拍摄前添加时延以实现定时拍摄
vTaskDelay(1000);
ret = bl_cam_mjpeg_get(&pic, &len);
遇到的问题
- SDK中建立socket连接的代码有bug
解决:修正代码
- python接收图片时没接收完就开始接收下一张图片
通过一个while循环,每次接收后检查剩余需接收的长度,直到接收完为止
未来的计划
- 
- 添加图形界面,使操作更加便捷
- 这次由于时间安排没来的及去做项目二至三,接下来会去尝试完成
 
附件:
- 可烧录的二进制文件(按成果展示中的步骤烧录):链接:https://pan.baidu.com/s/1MsKDigVceksZ717xLo97UQ 
 提取码:73mq
 --来自百度网盘超级会员V2的分享
- python源码:链接:https://pan.baidu.com/s/1S5-fSrxQQ-JH0lKkjxNtJw 
 提取码:vaxh
 --来自百度网盘超级会员V2的分享
- C源码:链接:https://pan.baidu.com/s/1ClFEg_APGPcrlIxea6eRJw 
 提取码:mr40
 --来自百度网盘超级会员V2的分享
团队介绍
还没想好~~
团队成员
sqzr
评论
0 / 100
查看更多
猜你喜欢
基于 Sipeed M1s Dock 实现网络相机使用 Sipeed M1s Dock 的板载摄像头定时捕获当前画面,并通过 WiFi 将图片发送到同一网络下的 PC 服务程序。
topgear
1920
基于Sipeed M1s Dock实现的网络相机本项目基于Sipeed M1s Dock,运行PikaScript环境,应用Python控制开发板,通过摄像头实现照片的拍摄,通过网络传输拍摄的照片,实现为一个网络相机。同时提供桌面应用接收数据,控制拍照和视频录制。
HonestQiao
1168
基于Sipeed M1s Dock实现网络相机目标:完成一个基于Sipeed M1s Dock 的网络相机
具体要求:
完成相机驱动,定时拍摄图片,并将图片通过网络传到电脑或服务器,实现长时间拍摄
通过电脑端编程将图片合成为一个视频
Kita-Ikuyo
1758

