【视频监控】通过TCP协议搭建客户端和服务端使用OpenCV实现Linux开发板摄像头图像实时回传本地

news2024/11/16 1:01:00

一. 前言

本文主要实现了远程开发板摄像头画面实时传输回本地电脑进而达到视频监控功能。主要分为开发板客户端和电脑服务端的两部分代码讲解。

本文使用的是米尔的Remi Pi开发板,摄像头是米尔配套的MY-CAM003M,开发板Python环境为3.8,电脑Python3.9

效果展示如下:

电脑端画面显示

OpenCV远程监控

按下k键图片保存在本地

二. 代码展示

1. 开发板客户端代码

import socket
import struct
import time
import traceback
import cv2
import numpy as np


class Client(object):
    """客户端"""

    def __init__(self, addr_port=('192.168.43.242', 11000)):
        # 连接的服务器的地址
        self.addr_port = addr_port
        # 创建套接字
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 地址端口可以复用
        self.client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # 分辨率
        self.resolution = (320, 240)

    def connect(self):
        """链接服务器"""
        try:
            self.client.connect(self.addr_port)
            print('连接服务器成功')
            return True
        except Exception as e:
            traceback.print_exc()  # 打印原始的异常信息
            print('连接失败')
            return False

    def send2server(self, fps=60):
        """读摄像头数据 发送给服务器"""
        camera = cv2.VideoCapture('/dev/video0')  # 使用OpenCV原生的VideoCapture打开摄像头
        print('isOpened:', camera.isOpened())

        if not camera.isOpened():
            print("无法打开摄像头")
            return

        # Calculate the time to sleep between frames to achieve the desired FPS
        delay = 1.0 / fps

        while camera.isOpened():
            try:
                start_time = time.time()

                # Capture frame-by-frame
                ret, frame = camera.read()
                if not ret:
                    print("无法读取摄像头帧")
                    break

                # Resize and compress the frame
                frame = cv2.resize(frame, self.resolution)
                ret, img = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 50])  # Reduced quality for faster transmission

                # Convert to numpy array and then to binary data
                img_code = np.array(img)
                img = img_code.tobytes()

                # Get the data length
                length = len(img)

                # Pack the data and send it
                all_data = struct.pack('ihh', length, self.resolution[0], self.resolution[1]) + img
                self.client.send(all_data)

                # Calculate the processing time and sleep to maintain the frame rate
                elapsed_time = time.time() - start_time
                if elapsed_time < delay:
                    time.sleep(delay - elapsed_time)
            except Exception as e:
                camera.release()  # 释放摄像头
                traceback.print_exc()
                break

        camera.release()


if __name__ == '__main__':
    client = Client()
    if client.connect():
        client.send2server(fps=20)  # Set the desired FPS (e.g., 20 FPS)

(1)自己设置要连接的服务端ip和port

addr_port=('192.168.43.242', 11000)

(2)自己设置合适的分辨率(我这里和摄像头初始化文件v4l2-init.h保持一致)

self.resolution = (320, 240)

(3)使用cv2.VideoCapture函数打开摄像头设备,预先查看自己摄像头节点

camera = cv2.VideoCapture('/dev/video0')

(4)自行调整画质

 ret, img = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 50])

(5)自行设置分辨率

client.send2server(fps=20)

以上关键的参数直接影响了画面的清晰度以及流畅度,请大家根据自己的设备仔细调整,往往需要不断tradeoff才能达到最佳的效果

1.帧率(Frame Rate)

  • 定义:帧率是指每秒钟显示的图像帧数,通常以FPS(Frames Per Second)为单位。
  • 清晰度的影响:帧率对图像的清晰度影响较小,主要影响的是运动中的画面质量。在低帧率下,快速移动的物体可能会产生运动模糊或跳帧现象。
  • 流畅度的影响:帧率直接影响视频的流畅度。较高的帧率(如30FPS或60FPS)可以提供更流畅的视觉体验,使得视频播放时的动作更自然顺滑。较低的帧率(如15FPS或更低)会导致视频显得卡顿或不连贯。

2. 分辨率(Resolution)

  • 定义:分辨率是指图像的像素宽度和高度,常见的分辨率有640x480(VGA)、1280x720(HD)、1920x1080(Full HD)等。
  • 清晰度的影响:分辨率对图像的清晰度有直接影响。较高的分辨率意味着更多的像素数,可以呈现更细腻的画面细节。因此,分辨率越高,图像的清晰度就越高。
  • 流畅度的影响:较高的分辨率需要更多的计算资源进行处理和传输,可能会影响视频的流畅度。如果硬件或网络带宽不足,高分辨率视频可能会导致播放时卡顿或延迟。

3. 画质(Quality)

  • 定义:画质通常与图像压缩程度和编码质量相关,影响图像的细节、颜色和整体视觉效果。
  • 清晰度的影响:较高的画质意味着更少的压缩损失,可以保留更多的图像细节和真实感。例如,在JPEG压缩中,较低的压缩率(高画质)会使图像更清晰,而较高的压缩率(低画质)会导致图像模糊、出现伪影等问题。
  • 流畅度的影响:较高的画质通常意味着更大的数据量,这可能会增加传输和处理的负担,进而影响视频的流畅度。在低带宽或低性能设备上,高画质的视频可能会导致播放不流畅。

除此之外,硬件性能和网络带宽也是影响视频传输的重要因素。

2. 电脑服务端代码

import socket
import struct
import threading
import traceback
import cv2
import numpy as np
import os

class Server:
    def __init__(self):
        # 设置tcp服务端的socket
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置重复使用
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 绑定地址和端口
        self.server.bind(('192.168.43.242', 11000))
        # 设置被动监听
        self.server.listen(128)

    def run(self):
        while True:
            print('等待客户端连接')
            # 等待客户端连接
            client, addr = self.server.accept()
            print(f"客户端已连接: {addr}")
            ProcessClient(client).start()


class ProcessClient(threading.Thread):

    def __init__(self, client):
        super().__init__()
        self.client = client

        # 初始化图片保存的编号
        self.i = 0
        path = "E:/sample"
        os.makedirs(path, exist_ok=True)  # 如果文件夹不存在,创建它

        # 获取现有图片的最大序号
        file_list = [int(f.split('.')[0]) for f in os.listdir(path) if f.endswith('.jpg')]
        if file_list:
            self.i = max(file_list) + 1

    def run(self):
        while True:
            try:
                # 接收图片的长度和分辨率
                data = self.client.recv(8)
                if not data:
                    break
                length, width, height = struct.unpack('ihh', data)

                # 接收完整的图像数据
                img_data = b''  # 存放最终的图片数据
                while length > 0:
                    temp_data = self.client.recv(length)
                    if not temp_data:
                        break
                    img_data += temp_data
                    length -= len(temp_data)

                # 把二进制数据还原
                img_array = np.frombuffer(img_data, dtype='uint8')

                # 还原成图像
                image = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
                if image is None:
                    print("解码失败,接收到的图像数据可能有误。")
                    continue

                # 显示图像
                cv2.imshow('capture', image)

                # 保存图像
                k = cv2.waitKey(1)
                if k == ord('k'):
                    cv2.imwrite(f"E:/sample/{self.i}.jpg", image)  # 存储路径
                    print(f"保存图片: {self.i}.jpg")
                    self.i += 1

                if k == ord('q'):
                    break

            except Exception as e:
                print(f"发生错误: {e}")
                traceback.print_exc()
                break

        # 断开连接时关闭窗口
        self.client.close()
        cv2.destroyAllWindows()


if __name__ == '__main__':
    server = Server()
    server.run()

一些参数解释同上,同时按下k键可以将图片保存到指定路径,按下q键退出。

需要注意的是,需要先运行电脑服务端的程序等待连接,再运行开发板程序,顺序不能颠倒!

三. 后序

本次尝试是笔者第一次使用OpenCV实现视频传输的功能,难免有疏忽理解不到位之处欢迎大家交流指正,在查资料的过程中主要参考了下面这位老哥的文章

https://blog.csdn.net/weixin_47460769/article/details/116300354

除此之外还看到了几篇写的不错的文章放在下面

https://blog.csdn.net/rosen_er/article/details/119716012

https://gitee.com/indecisive/Linux_QT

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2046989.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java的jdk配置成功,但是输入java -version等,命令行没有任何反应

问题 Java下载后&#xff0c;手动配置环境变量&#xff0c;并且配置好&#xff0c;但是在命令行中无论输入java的什么都没有反应 解决方案 将手动配置的环境变量放到最前面 重新尝试 java -version命令

C++模板的特化

目录 一、模板特化概念 二、函数模板特化 三、类模板特化 1.全特化 2.偏特化 3.总结 4.类模板特化实例应用 一、模板特化概念 函数模板和类模板都有特化&#xff1a; 通常情况下使用模板可以实现一些与类型无关的代码&#xff0c;但一些特殊类型可能会出错&#xff0c;…

报错:Can‘t find Python executable “python“, you can set the PYTHON env variable

将项目导入vscode,执行npm install命令后&#xff0c;报错了&#xff0c;报错的信息是node-sass安装失败&#xff0c;同时提示需要python环境的错误信息&#xff0c;这是因为安装node-sass失败了&#xff0c;而node-sass依赖于Python环境。 1.报错&#xff1a;Cant find Python…

基于Hadoop的微博社交媒体用户大数据分析【海量数据】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍数据集展示Hadoop脚本文件可视化展示每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 本项目基于hadoop的社交媒体用户进行大数据…

把照片制作成精美的仿真电子相册

​在这个数字化时代&#xff0c;我们拍摄的照片越来越多&#xff0c;但往往缺乏一个合适的方式来展示和保存这些珍贵的回忆。今天&#xff0c;我将向大家介绍如何将你的照片制作成一个精美的仿真电子相册&#xff0c;让你的回忆更加生动和持久。 第一步&#xff1a;选择合适的照…

FreeRTOS 3

一&#xff0c;信号量 有时候任务之间传递的只是一个标致&#xff0c;让进程之间同步&#xff0c;会对一个共享资源的互斥性访问&#xff0c;这时候就可以用信号量和互斥量。 1&#xff0c;二值信号量 2&#xff0c;计数信号量 3&#xff0c;互斥量 3.1&#xff0c;差别 4&…

Orangepi 5 Pro(香橙派5pro)部署yolov5

前言 香橙派内置了6T算力的NPU&#xff0c;想着可以跑一下yolov5&#xff0c;看看香橙派的速度如何。 在开始部署之前&#xff0c;需要具备一定的linux技能——vim、linux常见指令、conda等等。如果没有这些技能的话&#xff0c;做下去会有一定的难度&#xff0c;可以先看几遍了…

19.实现一个算法实现删除链表中倒数第 n 个结点

19. Remove Nth Node From End of List 题目 Given the head of a linked list, remove the nth node from the end of the list and return its head. Follow up: Could you do this in one pass? Example 1: Input: head = [1,2,3,4,5], n = 2 Output: [1,2,3,5]Example…

蚂蚁AL1 15.6T 创新科技的新典范

● 哈希率&#xff1a;算力达到15.6T&#xff08;相当于15600G&#xff09;&#xff0c;即每秒能够进行15.6万亿次哈希计算&#xff0c;在同类产品中算力较为出色&#xff0c;能提高WA掘效率。 ● 功耗&#xff1a;功耗为3510W&#xff0c;虽然数值看似不低&#xff0c;但结合其…

PythonStudio 控件使用常用方式(二十七)TActionList

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;官网地址是&#xff1a;https://glsite.com/ &#xff0c;在官网可以下载最新版的PythonStudio&#xff0c;同时&#xff0c;在使用PythonStudio时&#xff0c;它也能及时为用户升到最新版本。它使用的是Delphi的控件&…

Python爬虫技术与K-means算法的计算机类招聘信息获取与数据分析

有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 目录 摘要.... 1 Abstract 2 1 引言.... 3 1.1 研究背景... 3 1.2 国内外研究现状... 4 1.3 研究目的... 5 1.4 研究意义... 7 2 关键技术理论介绍... 7 2.1 Python爬虫... 7 2.1 K-means…

消灭星星游戏程序设计【连载十一】——在线程中解决音效卡顿问题

消灭星星游戏程序设计【连载十一】——在线程中解决音效卡顿问题 大家每次都可以在页面中下载本节内容的实现代码&#xff0c;一步一步从简单开始&#xff0c;逐步完成游戏的各种功能&#xff0c;如果大家有任何问题也欢迎留言交流。 游戏整体效果展示&#xff1a; 1、本节要达…

宠物空气净化器哪款好?希喂、有哈宠物空气净化器测评

回想起几年前那个午后&#xff0c;我意外的在路边捡到了两只小猫咪&#xff0c;心中莫名有一份责任感出现&#xff0c;所以没有丝毫犹豫我就决定将它们带回家。捡回家以后&#xff0c;家里确实多了几分温馨&#xff0c;逐渐成为我的精神支柱。小猫的到来&#xff0c;让家的每一…

Mybatis工具类的封装

为什么要进行Mybatis工具类的封装&#xff1f; 每次我们执行数据库操作都需要做以下操作&#xff1a; //读取配置文件InputStream inputStream Resources.getResourceAsStream("mybatis-config.xml");//通过配置文件创建SqlSessionFactorySqlSessionFactory sqlSess…

模板[C++]

目录 1.&#x1f680;泛型编程&#x1f680; 2.&#x1f680;函数模板&#x1f680; 2.1 ✈️函数模板概念✈️ 2.2 ✈️函数模板格式✈️ 2.3✈️函数模板的原理✈️ 2.4 ✈️函数模板的实例化✈️ 2.5 ✈️模板参数的匹配原则✈️ 3.&#x1f680;类模板&#x1f680…

Ubuntu20.4 系统安装后无wifi图标

0. 问题排查 1.检查 BIOS 设置: 有时候&#xff0c;无线网卡可能在 BIOS 中被禁用。重启电脑&#xff0c;进入 BIOS 设置&#xff0c;确保无线网卡选项是启用的。 2.检查硬件开关: 检查您的笔记本电脑是否有物理开关或键盘快捷键来启用或禁用无线网卡。 3.在软件更新中切换…

Codeforces Round 495 (Div. 2) F. Sonya and Bitwise OR(线段树)

原题链接&#xff1a;F. Sonya and Bitwise OR 题目大意&#xff1a; 给出一个长度为 n n n 的数组 a a a&#xff0c;并给出 m m m 次询问以及一个数字 x x x。 每个询问形式如下给出&#xff1a; 1 1 1 i i i y y y &#xff1a;将 a i a_{i} ai​ 位置的值更改为 y…

将2,3,4,5,6,8分别填入算式“口口口X口口口“的“囗“中,怎么填使得算式结果最大。

一、解题思路 将数组元素进行全排列&#xff1a;对整个数组进行全排列&#xff0c;这样我们可以避免手动选择组合、排列剩余元素等步骤。 直接分割排列后的数组&#xff1a;在每一个全排列中&#xff0c;前3个元素和后3个元素自然形成了一个组合和一个剩余元素组合。 计算并…

Linux安装redis和使用redisDesktop连接

目录 Linux安装redis及启动 第一步&#xff1a;下载redis压缩包 第二步&#xff1a;下载gcc-c 第三步&#xff1a;解压redis文件 第四步&#xff1a;进入redis-4.0.0.0目录执行make命令 第五步&#xff1a;安装redis到redis目录 第五步&#xff1a;复制redis.conf配置文件…

电脑开机LOGO修改教程_BIOS启动图片替换方法

准备工具&#xff1a;刷BIOS神器和change logo&#xff0c;打包下载地址&#xff1a;https://download.csdn.net/download/baiseled/89374686 一.打开刷BIOS神器&#xff0c;点击备份BIOS&#xff0c;保存到桌面 二.打开change logo&#xff0c;1.点击load image&#xff0c;选…