博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UDP实时图像传输
阅读量:3931 次
发布时间:2019-05-23

本文共 4678 字,大约阅读时间需要 15 分钟。

〇、写在前面

首先问个问题,为什么要用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);//将套接字的监听队列长度限制为20socketWatch.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
img = currentImage.ToImage
();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、UDPusing System.Net;using System.Net.Sockets;//多线程using System.Threading;//使用EmguCV读取摄像头using Emgu.CV;using Emgu.CV.Structure;//接收端读取图像using System.IO;

项目都已上传至

----------- 2020.5.14更新 -----------

由于一个UDP数据包只能发送64k字节的数据,所以本文方法能传输的图像大小有限制,更高清晰度图像的传输见

----------- 2020.8.28更新 -----------

TCP对传输的数据大小没有限制,且能保证传输的可靠性,详见

转载地址:http://tlvgn.baihongyu.com/

你可能感兴趣的文章
source build/envsetup.sh 之后
查看>>
android的jni语法
查看>>
android打包so文件到apk
查看>>
android-jni 之 环境搭建
查看>>
安装cygwin
查看>>
源码编译-app
查看>>
eclipse生成的apk和系统编译产生的apk有何不同
查看>>
NDK-Android.mk 英文编译说明
查看>>
Build system 英文说明 -- Andrlid.mk说明
查看>>
This attribute must be localized”
查看>>
Android.mk 使用 环境 小结
查看>>
android通过 哪些变量 来决定 哪些应用 会被编译进系统
查看>>
Android的语言设置-跟踪
查看>>
Android 电源管理 -- wakelock机制
查看>>
android设置中PreferenceActivity的 小结
查看>>
Android ListPreference的用法
查看>>
android“设置”里的版本号
查看>>
源码开发-小结
查看>>
Preference 的xml使用 小结
查看>>
java里的throws 和 try-catch 的用法
查看>>