UDP实时图像传输

2023-05-16

〇、写在前面

首先问个问题,为什么要用UDP传输图像,而不是TCP?

TCP是我们经常使用的通信协议,从认识它的第一天起,就应该知道,它非常稳,丢包率超低。但是一切都有双面性,稳定会影响传输的速度。与TCP不同,UDP没有反复确认这个环节,发送端向一个接收端甩一个数据包,不管接收端有没有接收到,所以相较于TCP,其丢包率比较大,但是它的速度就快多了。针对图像传输这种耗时但是不追求准确性的任务,采用UDP是再合适不过的了。目前许多网络直播都采用UDP来传输图像。

接下来描述一下主要内容,使用C#窗体在两台PC上分别创建一个图像发送端和一个图像接收端,发送端采集摄像头图像,压缩为JPEG格式后使用UDP发送至接收端,接收端接收图像并进行显示。
在这里插入图片描述
所以本项目主要有以下两部分:
 图像发送端的搭建
 图像接收端的搭建

另外这个项目还会用到TCP来确认双方是否都在线,如果接收方还没准备好,发送方就开始发图像了,那就是在做无用功了(虽然对这个项目来说影响不大)。具体的做法就是主机A(发送端)作为TCP服务端,创建一个套接字,绑定一个IP和端口Port,开启监听。主机B作为TCP客户端,连接到主机A创建的服务端。连接后,主机A打开摄像头,并开始向主机B发送图像。
在这里插入图片描述
TCP服务端(主机A):

Thread threadWatch = null; //负责监听客户端的线程
Socket socketWatch = null;  //负责监听客户端的套接字
 
/****创建套接字*****/
//定义一个套接字用于监听客户端发来的信息  包含3个参数(IP4寻址协议,流式连接,TCP协议)
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//服务端发送信息 需要1个IP地址和端口号
IPAddress ipaddress = IPAddress.Parse(this.comboBox1.Text.Trim()); //获取文本框输入的IP地址
//将IP地址和端口号绑定到网络节点endpoint上 
IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse(this.comboBox2.Text.Trim())); //获取文本框上输入的端口号
//监听绑定的网络节点
socketWatch.Bind(endpoint);
//将套接字的监听队列长度限制为20
socketWatch.Listen(20);
//创建一个监听线程 
threadWatch = new Thread(WatchConnecting);
//将窗体线程设置为与后台同步
threadWatch.IsBackground = true;
//启动线程
threadWatch.Start();

/****监听客户端发来的请求*****/
//创建一个负责和客户端通信的套接字 
Socket socConnection = null;
private void WatchConnecting()
{
    while (true)  //持续不断监听客户端发来的请求
    {
        socConnection = socketWatch.Accept();
	}
}

TCP客户端(主机B):

private void startBtn_Click(object sender, EventArgs e)
{
        //Parse:将一个字符串的ip地址转换成一个IPAddress对象
        IPAddress ipaddress = IPAddress.Parse(comboBox1.Text);
        EndPoint point = new IPEndPoint(ipaddress, int.Parse(comboBox2.Text));
        Thread connect = new Thread(new ParameterizedThreadStart(Connect));
        connect.Start(point);
}
//连接线程
private static void Connect(object point)
{
    try
    {
        Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        tcpClient.Connect((EndPoint)point);//通过IP和端口号来定位一个所要连接的服务器端
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

最后,两个项目都是用VS2017生成的,.NET框架为4.7.1.
接下来进入正文

一、图像发送端的搭建

首先需要获取摄像头图像,这里使用EmguCV来获取图像以及转码。

点击 工具->NuGet包管理器->管理解决方案的NuGet程序包,在浏览那一栏查找Emgu.cv,选择第一个,在右侧选择要安装EmguCV的项目,点击安装即可。
在这里插入图片描述
在这里插入图片描述
因为这个项目只用到了EmguCV的读取摄像头功能,就不再赘述了,如果还想深入了解EmguCV,欢迎交流

EmguCV就这样安装好了。然后就可以调用EmguCV中的函数获取摄像头数据了

private VideoCapture capture = new VideoCapture();
Mat currentImage = capture.QueryFrame();

currentImage就是获取的摄像头图像,默认尺寸是640*480,可以通过以下代码更改设置

capture.SetCaptureProperty(CapProp.FrameWidth, 720);
capture.SetCaptureProperty(CapProp.FrameHeight, 1280);

接下来将图像转化成UDP发送的byte[]格式。一个UDP数据包只能发送64k字节数据,也就是65536字节,但是一帧图片就有640x480x3=921600byte=900k字节,所以需要进行图像压缩,这里采用jpeg压缩格式。

Image<Rgb,Byte> img = currentImage.ToImage<Rgb, Byte>();
byte[] bytes = img.ToJpegData(80);

最后使用UDP进行发送。

UdpClient udpClient = new UdpClient();
//接收端绑定的IPAddress、端口号
IPAddress ipaddress = IPAddress.Parse("10.128.14.249");
IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse(this.comboBox2.Text.Trim()));
udpClient.Send(bytes, bytes.Length, endpoint);
udpClient.Close();

二、图像接收端的搭建

在设计面板上添加一个PictureBox控件,用来显示接收到的图像,添加一个Button,用来建立和发送端的连接。

接下来创建一个UDP的套接字,绑定本地IPv4地址,

Socket udpServer = null;

//创建套接字
udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//绑定IP和端口
udpServer.Bind(new IPEndPoint(GetLocalIPv4Address(), 8090));
//开启接收数据线程
new Thread(ReceiveMessage)
{
    IsBackground = true
}.Start();

如果不知道本地IPv4地址,可以使用以下函数自动获取,这样也可以避免以后IPv4地址改变而报错

public IPAddress GetLocalIPv4Address()
{
    IPAddress localIpv4 = null;
    //获取本机所有的IP地址列表
    IPAddress[] IpList = Dns.GetHostAddresses(Dns.GetHostName());
    //循环遍历所有IP地址
    foreach (IPAddress IP in IpList)
    {
        //判断是否是IPv4地址
        if (IP.AddressFamily == AddressFamily.InterNetwork)
        {
            localIpv4 = IP;
        }
        else
        {
            continue;
        }
    }
    return localIpv4;
}

最后就可以开始接收图像了

void ReceiveMessage()
{
    while (true)
    {
        EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        //设置一个64k的字节数组作为缓存
        byte[] data = new byte[65536];
        int length = udpServer.ReceiveFrom(data, ref remoteEndPoint);//此方法把数据来源ip、port放到第二个参数中

        MemoryStream ms = new MemoryStream(data, 0, length);
        pictureBox1.Image=Image.FromStream(ms);
    }
}

最终效果:
发送端
接收端

一些注意事项

需要在开头添加以下代码

//TCP、UDP
using System.Net;
using System.Net.Sockets;

//多线程
using System.Threading;

//使用EmguCV读取摄像头
using Emgu.CV;
using Emgu.CV.Structure;

//接收端读取图像
using System.IO;

项目都已上传至https://download.csdn.net/download/qq_42688495/11872026

----------- 2020.5.14更新 -----------
由于一个UDP数据包只能发送64k字节的数据,所以本文方法能传输的图像大小有限制,更高清晰度图像的传输见UDP实时图像传输进阶篇——1080P视频传输

----------- 2020.8.28更新 -----------
TCP对传输的数据大小没有限制,且能保证传输的可靠性,详见TCP实时图像传输

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UDP实时图像传输 的相关文章

  • qt画个灰度直方图

    步骤 导入图表库在ui界面新建一个wight窗口并提升为那个图表库的类型写函数 输入参数是 xff08 图表 xff0c 待处理图片 xff09 图表的横轴是像素值 从0 255 纵轴是此灰度的像素点数量或者占比所以要挨个判断图像里的每一个
  • 找特征点的算法 SIFT和SURF算法

    SIFT 特征点算法 SIFT算法是记录每个极值点附近的梯度方向 xff0c 并以一个主要梯度方向为基准来兼顾特征旋转的情况 它通过不同模糊程度的灰度图相减找极值 xff0c 筛选确定出真实关键点后按梯度和权重求出关键点的主方向 xff0c
  • nano的CAN通信

    我买的是微雪的树莓派用的SPI转CAN 现在用在jetson nano上 我看了一下俩模块的芯片用的都是一样的 xff0c 引脚也都对得上 xff0c 所以我就打算拿这个模块给nano做can通信 具备CAN功能 xff0c 使用SPI接口
  • 驱动开发基础知识——设备树

    BSP开发工程师 原来BSP就是那些被指臃肿的文件啊 BSP的出生 Linux经过不断的发展 原先嵌入式系统的三层结构逐步演化成为一种四层结构 这个新增加的中间层次位于操作系统和硬件之间 包含了系统中与硬件相关的大部分功能 通过特定的上层接
  • 分布式系统 中间件

    我只是想知道中间件是什么而已 xff0c 结果 中间件 61 平台 43 通信 xff0c 这也就限定了只有用于分布式系统中才能叫中间件 xff0c 同时也把它与支撑软件和实用软件区分开来 中间件技术能屏蔽底层操作系统的复杂性 xff0c
  • 伺服电机控制

    前言 xff1a 感谢各位大佬愿意将知识开源并作出详细的说明 我只是依据自己的学习轨迹稍作整理 xff0c 加以自己的理解并记录于此 本文几乎所有的参考内容都附上了原文链接 xff0c 本文的文字内容有一些是我的 xff0c 有一些是从链接
  • 永磁同步电机的MATLAB建模

    建模是为了能够确定我们输入怎样的电压能得到怎样的转矩 xff0c 以获得怎样的转速 电机这个东西 xff0c 输出的不是位移也不是速度 xff0c 我们要看的输出是力矩 xff0c 力矩够大才有位移才有速度 xff0c 没有位移没有速度的时
  • SVPWM的MATLAB建模

    异步电机矢量控制20讲 xff1a SVPWM的simulink仿真 xff08 总第38讲 xff09 扇区判断 注意 xff0c 这个N是二进制转来的十进制数 波形对应出来的扇区是 5 6 1 2 3 4 如果改变三相电压输入的相位 x
  • Java要素察觉

    简介 xff1a 主要内容来源于b站刘二大人Java课程 xff0c 旨在记录课程中的重要内容 Java课程记录 xff08 课程号作为标题 xff09 02 数据类型03 数组与字符串05 类与对象07 继承08 方法重载 方法重写和多态
  • vscode配置gitee(码云)实现步骤

    第一步 1 百度搜索Git xff0c 出现的第一个网站 xff08 如下图 xff09 Git xff09 2 下载 3 下载之后 双击安装 xff08 安装过程中只需要默认下一步 不需要多余操作 放心大胆的点击下一步 xff09 第二步
  • ROS读取MPU6050数据

    上一篇讲到使用I2C连接Jetson Nano和MPU6050并使用python读取 xff0c 本次基于roscpp连接读取IMU数据 RTIMULib RTIMULib是本次使用的IMU库 xff0c 支持多种常见的IMU模块 xff0
  • 关于navicat报错:Server unexpectedly closed network connection

    破解navicat后 使用navicat连接本地虚拟机 发现出现以下错误 在百度以及谷歌上面查找很多博客 发现我这里的报错信息跟他们不一样 解决方法 1 打开本地虚拟机 进入mysql mysql span class token oper
  • 学会查看官方文档

    曾经经历过的误区 从刚开始接触编程开始 xff0c 基本上接触新事物 xff0c 第一件事情就是去找博客 xff0c 或者买书 往往只需要使用的一个很小的知识点 xff0c 却购买了好几本不同的书籍 事后证明 xff0c 并没有什么太大的用
  • QGroundControl如何进行二次开发

    QGroundControl如何进行二次开发 QGroundControl是一个开源的地面站软件 xff0c 你可以通过以下步骤进行二次开发 xff1a 1 下载并安装QGroundControl 首先需要从QGroundControl的官
  • C 结构体指针malloc分配问题

    C语言中关于结构体指针的内存分配问题 话不多说先上一段代码 span class token keyword typedef span span class token keyword struct span span class toke
  • 这是一个用于记录学习经验的博客

    写在前面 本科时期科研经历较少 xff0c 硕士期间越来越多地开始接触计算机相关的软件 算法 项目等 从2020年入学至今 xff0c 也学习到了一些相关的知识与经验 过去都是通过word的方式记录进展与经验 从今天起我也想尝试通过博客的方
  • ARM64架构的Linux系统中编译C++程序报错fatal error: sys/io.h: No such file or directory

    原因是不同的Linux平台的 io h 放置的位置不同 Windows下的io h直接包含即可 xff1b Linux平台下在sys文件夹下 xff1b ARM架构的系统中在sys文件夹下 xff0c 而且名字也不一样 xff0c 变成了u
  • 矩阵的QR分解

    Gram Schmidt正交化 在提到矩阵的QR分解前 xff0c 必须要提到Gram Schmidt方法 xff0c 理论上QR分解是由Gram Schmidt正交化推出来的 那么Gram Schmidt正交化究竟是什么 在三维空间存在直
  • 常见数学符号及其读法

    大写 小写 英文注音 国际音标注音 中文注音 alpha alfa 阿耳法 beta beta 贝塔 gamma gamma 伽马 deta del
  • cartographer环境配置及运行

    文章目录 1 首先安装ROS2 安装eigen33 安装ceres4 安装cartographer5 试运行总结 xff1a 系统 xff1a Ubuntu 18 04 1 首先安装ROS 在无网络限制的情况下参考官网安装 ref xff1

随机推荐

  • SLAM会议笔记(一)LOAM

    LOAM Lidar Odometry and Mapping in Real time ABSTRACT 将复杂的SLAM问题分离为两个算法 xff0c 一个高频低精度的运动估计 xff0c 另一个低一个数量级的点云匹配和配准算法 REL
  • 相机&IMU内参及外参标定

    1 使用工具 xff1a https github com ethz asl kalibr git 2 特点支持多个相机的内参外参标定 xff0c 即使视域没有重叠 xff1b 支持相机 amp IMU之间标定 xff1b 支持IMU与IM
  • SLAM会议笔记(二)Real-time DEMO

    Real time Depth Enhanced Monocular Odometry Abstract 利用图像和稀疏的深度图做运动估计 xff0c 同时利用三角量测和运动估计得到位置深度的突出图像特征点的深度 xff0c 使用光束平差法
  • SLAM会议笔记(三)V-LOAM

    Visual lidar Odometry and Mapping Low drift Robust and Fast Abstract 提出了一种新的使用激光雷达里程计和视觉里程计的框架 xff0c 提升了表现 xff0c 特别是在剧烈运
  • SLAM会议笔记(四)Lego-LOAM

    LeGO LOAM Lightweight and Ground Optimized Lidar Odometry and Mapping on Variable Terrain Abstract 提出一种轻量级的ground optimi
  • SLAM会议笔记(五)LLOAM

    LLOAM LiDAR Odometry and Mapping with Loop closure Detection Based Correction Abstract 在LOAM的基础上加入了回环检测 xff0c 实现了雷达SLAM的
  • C++基础:第三章 对象与基本类型

    文章目录 第3章 对象与基本类型第1节 初始化 赋值语句第2节 类型详述类型描述类型种类划分与类型相关的标准未定义部分变量 第3节 复合类型 xff1a 从指针到引用指针指针特点相关操作符指针的定义 96 void 96 指针指针的指针指针
  • C++基础:第四章 数组、vector和字符串

    文章目录 第4章 数组 vector和字符串第1节 数组注意事项数组的复杂声明数组中元素的访问数组到指针的隐式转换获得s指向数组开头和结尾的指针数组的其他操作C字符串多维数组 第2节 vector构造和初始化元素的索引和遍历迭代器itera
  • C++基础:第五章 表达式基础与详述

    第五章 表达式基础与详述 第1节 基础 xff1a 引入 表达式由一到多个操作数组成 xff0c 可以求值并 xff08 通常会 xff09 返回求值结果 xff08 函数的调用是一种表达式 xff0c 有时函数不会返回求值结果 xff09
  • C++基础:第六章 语句

    第六章 语句 第1节 语句基础 常见类别 xff1a 表达式语句 xff0c 求值后丢弃 2 43 3 空语句复合语句 xff0c 用大括号 xff0c 形成独立的域 顺序语句 按先后顺序执行实际执行顺序可能产生变换 xff08 编译器优化
  • C++基础:第七章 函数

    第七章 函数 第1节 函数基础 栈帧结构 函数的外部链接 第2节 函数详解 传值 传址 传引用 传参数时的类型退化 xff0c 传数组时函数形参退化成指针 xff0c 所以形参不要写数组个数 多维数组作为函数参数时 void fun int
  • C++基础:第八章 深入IO

    第八章 深入IO 第1节 序 第2节 IOStream概述 流式IO而非记录IO 处理的主要问题 表示形式的变化 xff1a 使用格式化 解析在数据的内部表示与字符序列之间切换与外部设备的通信 xff1a 针对不同的外部设备引入不同的处理逻
  • 在vscode终端安装vue构建工具vite

    首先确保已安装npm 第一步 xff1a 全局安装yarn 0 打开cmd xff08 windows 43 R xff09 1 输入安装命令 npm install g yarn 2 如果能看到版本号 xff0c 则安装成功 yarn v
  • cmake相关:sudo make install后的卸载

    sudo make install后的卸载 我们知道linux中一般的编译一个package的顺序是 span class token function git span clone package git span class token
  • 提取rosbag中的图像话题存为本地图像

    新建存放图片文件夹 首先运行ros master roscore 在目标文件夹目录下运行 rosrun image view extract images sec per frame 61 0 05 image 61 lt ROSIMAGE
  • matlab循环读取文件

    一般情况下 xff0c 假如我要读取一个名为a txt的文件 xff0c 只需要利用下面的语句 xff1a a span class token operator 61 span span class token function load
  • 使用OpenMVG获取相机位姿的方法

    在生成sfm data bin文件后 xff0c 在文件目录下执行 openMVG main ConvertSfM DataFormat binary span class token operator span i yoursfm dat
  • Ubuntu修改文件夹下面所有文件权限的方法

    ubuntu修改文件夹下所有文件的权限 命令为 xff1a sudo chmod span class token operator span R 777 filename filename为要修改的文件夹名字 R应该是表示递归修改file
  • 写出对js事件,事件流,事件对象的理解

    事件 JavaScript 使我们有能力创建动态页面 事件是可以被 JavaScript 侦测到的行为 网页中的每个元素都可以产生某些可以触发 JavaScript 函数的事件 比方说 xff0c 我们可以在用户点击某按钮时产生一个 onC
  • UDP实时图像传输

    写在前面 首先问个问题 xff0c 为什么要用UDP传输图像 xff0c 而不是TCP xff1f TCP是我们经常使用的通信协议 xff0c 从认识它的第一天起 xff0c 就应该知道 xff0c 它非常稳 xff0c 丢包率超低 但是一