UDP实时图像传输

〇、写在前面

首先问个问题,为什么要用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实时图像传输

  • 15
    点赞
  • 174
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: 使用Unity进行UDP图像传输需要以下步骤: 1. 在Unity项目中创建一个可以接收和发送UDP数据包的脚本。 2. 使用Unity的网络库来实现UDP数据包的接收和发送功能。可以使用Unity自带的Network类或第三方库如UNET或LiteNetLib。 3. 在脚本中定义接收和发送数据包的函数。接收函数应该监听指定的UDP端口,并处理接收到的图像数据。发送函数应该将图像数据打包成UDP数据包,并使用目标IP地址和端口发送出去。 4. 在Unity场景中创建一个用于图像显示的对象,比如一个Plane或一个RawImage。将接收到的图像数据应用到该对象的纹理中,实现图像的显示。 5. 在脚本中实现实时图像传输的逻辑。例如,在Update函数中不断调用发送函数发送图像数据,或者在接收到新的图像数据时立即更新图像显示对象。 6. 在需要发送图像的端口启动一个UDP服务器,用于接收发送端的图像数据,并将其发送给接收端。 需要注意的是,UDP是无连接的协议,它不能保证数据传输的可靠性和顺序。因此,在实现图像传输时,可以加入一些数据校验和错误检测的机制来确保图像数据的正确性。 此外,需要注意图像传输会消耗大量的带宽和计算资源。因此,在实际应用中可能需要对图像进行压缩或降低分辨率以减少数据量,并进行性能优化以确保流畅的图像传输。 ### 回答2: 要通过Unity实现UDP图像传输,可以按照以下步骤进行操作: 1. 首先,确保你已经安装了Unity开发环境,并创建了一个新项目。 2. 打开Unity中的Asset Store,并搜索并下载相应的网络库,如UNET(Unity Networking)。 3. 导入所下载的网络库至Unity项目中。 4. 在Unity项目中创建两个场景,分别命名为"发送端"和"接收端"。 5. 在发送端场景中,创建一个3D对象,将其作为摄像机,用于捕捉图像。 6. 编写脚本,将摄像机捕捉到的图像数据转换为字节数组,并通过UDP协议发送给接收端。 7. 在接收端场景中,创建另一个3D对象作为摄像机,用于接收和显示图像。 8. 编写脚本,接收UDP数据并将其转换为图像,并将其应用于摄像机的纹理上,以显示传输图像。 9. 在发送端和接收端的脚本中,使用Unity Networking库中提供的UDP API,如NetworkTransport类,来发送和接收UDP数据。 10. 在Unity编辑器中,分别运行发送端和接收端场景进行测试。 通过以上步骤,你就可以在Unity中使用UDP实现图像传输了。需要注意的是,在实际的网络环境中,还需考虑网络延迟、丢包等问题,并进行相应的优化和处理,以保证图像传输的稳定性和实时性。 ### 回答3: Unity是一款强大的游戏引擎,可以通过UDP(User Datagram Protocol)实现图像传输。以下是实现图像传输的步骤: 1. 创建Unity项目:首先,我们需要在Unity中创建一个新的项目。可以选择2D或3D模板,具体根据实际需求进行选择。 2. 导入网络库:Unity本身不支持UDP协议,因此我们需要导入一个网络库来实现UDP通信。常用的网络库有UNET、LiteNetLib等。通过导入和配置网络库,我们可以在Unity项目中使用UDP。 3. 创建服务器和客户端:在Unity中,我们需要创建一个服务器和一个或多个客户端来实现图像传输。服务器负责接收图像数据并将其转发给客户端,客户端则负责接收并显示图像。 4. 编写脚本:为了实现UDP图像传输,我们需要编写相关的脚本。针对服务器端,我们需要实现接收图像数据的功能,并将其转发给客户端。对于客户端,我们需要实现接收图像数据并显示在屏幕上的功能。 5. 配置网络连接:通过在Unity中配置网络连接,我们可以让服务器和客户端之间建立UDP通信。配置网络连接需要指定服务器的IP地址和端口号,并使用相应的API建立连接。 6. 实现图像传输:通过编写脚本和配置网络连接,我们可以实现图像传输功能。服务器端接收图像数据后,将其转发给客户端进行显示。客户端通过接收服务器发送的图像数据,并在屏幕上显示出来。 总结起来,要实现Unity中的UDP图像传输,我们需要导入网络库,创建服务器和客户端,编写脚本,配置网络连接,并最终实现图像传输功能。这样,我们就可以在Unity中通过UDP实现图像传输了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值