在UDP实时图像传输一文中,介绍了如何使用UDP来实现图像的实时传输,并使用C#进行了发送端和接收端的搭建。但是文中的方法是对整张图片进行JPEG压缩,并通过UDP一次性地发送到接收端,由于一个UDP数据包只能发送64k字节的数据,所以该方法的图片传输大小是有限制的,实测只能发送480P视频中的图像。

所以本文将继续采取逐帧发送的形式,以1080P的视频为例,实现更高清晰度(1080×1920×31080\times 1920\times 31080×1920×3)的图像实时传输。

基本流程

本文中的高清晰度图像传输就是在前文方法的基础上,在发送端添加了切片压缩传输以及并行加速的步骤,而接收端则相应地使用多线程进行数据接收,分别接收压缩后的切片数据,再拼接起来进行显示。流程如下

实验环境

  • VS2019 / .NET4.7.1 / C#(开发环境)

  • EmguCV 4.1(用于读取、压缩图像,使用方法见上一篇文章)

  • PC(测试环境)

发送端

在发送端我们需要达到的效果如下,左边用来显示原始图像,右上角用来显示各个切片,右下角用来处理接收端的连接请求。

首先设置一些参数

// 实例化一个VideoCapture,选择从本地文件读取视频
private VideoCapture capture = new VideoCapture("../../video/04.mp4");
// 设置读取的图片宽度
const int WIDTH = 1920;
// 设置读取的图片高度
const int HEIGHT = 1080;
// 切片数量
const int NUM_SLICE = 24;

然后进行图像的显示以及切片。初始化一组显示控件,用来显示切片后的结果:

private void Form1_Load(object sender, EventArgs e)
{// 设置图像大小capture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth, WIDTH);capture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight, HEIGHT);// 获取面板控件的大小int w = panel_imgs.Width;int h = panel_imgs.Height;// 在面板panel_imgs上添加显示控件,用于显示每个切片for (int i = 0; i < NUM_SLICE; i++){ImageBox imgb = new ImageBox();imgb.Left = 0;imgb.Top = i * h / NUM_SLICE;imgb.Width = w;imgb.Height = h / NUM_SLICE - 1;imgb.SizeMode = PictureBoxSizeMode.StretchImage;imgb.Visible = true;imgbox[i] = imgb;panel_imgs.Controls.Add(imgbox[i]);}// 在下拉文本框cbb_localIP中显示该计算机中的IPv4地址cbb_localIP.Text = GetLocalIPv4Address().ToString();
}

最后就是图像的读取、切片、压缩、发送等处理函数,这处理过程中,使用了Parallel.For并行加速功能,相对于串行的for循环,并行速度提高了一倍左右(不知道为啥我四核八线程的处理器只能降低一半的运行时间)

private void ProcessFram() // 图像读取、切片、发送
{DateTime startDT = System.DateTime.Now;while (true){// 计算两次循环间的间隔,并显示在左上角DateTime stopDT = System.DateTime.Now;TimeSpan ts = stopDT.Subtract(startDT);this.Text = "图片处理耗时:" + ts.TotalMilliseconds + "ms";startDT = System.DateTime.Now;// 读取一张图片Mat currentImage = capture.QueryFrame();// 显示摄像头/视频流的图像imageBox0.Image = currentImage;int N = HEIGHT / NUM_SLICE;// 对图像进行切片,并将切片压缩后发送到接收端                Parallel.For(0, NUM_SLICE, i => // Parallel并行加速{// 从原图中切割,输入参数:原始图片 行范围row 列范围colimg[i] = new Mat(currentImage, new Range(i * N, (i + 1) * N - 1), new Range(0, WIDTH));// 显示imgbox[i].Image = img[i];// 转换格式Image<Rgb, Byte> img_trans = img[i].ToImage<Rgb, Byte>();// JPEG压缩byte[] bytes = img_trans.ToJpegData(95);// UDP配置UdpClient udpClient = new UdpClient();//IPAddress ipaddress = IPAddress.Parse("192.168.0.105");IPAddress ipaddress = remoteIP;IPEndPoint endpoint = new IPEndPoint(ipaddress, 8000 + 10 * i);// UDP发送udpClient.Send(bytes, bytes.Length, endpoint);udpClient.Close();});}
}

在初始化函数中添加以下程序就可以执行包含切片、压缩、发送等操作的线程

Thread transFrames = new Thread(ProcessFram);
transFrames.Start();

接收端

接收端比较简单,实现效果如下,因为在接收端没有对图片进行更进一步的处理,所以本文只在接收端添加了若干个显示控件,用来显示每个切片,但是从观感上每个切片依次连接,形成了一张完整的图片。

首先进行参数设置

 // 切片数量,与发送端保持一致const int NUM_SLICE = 24; // 为每一个切片创建一个显示控件PictureBox[] imgbox = new PictureBox[NUM_SLICE];// 为每一个切片创建一个UDP套接字Socket[] udpServer = new Socket[NUM_SLICE];

在初始化过程中添加显示控件,与发送端类似

int w = panel_imgs.Width;
int h = panel_imgs.Height;
// 在面板panel_imgs上添加显示接收到的图片的控件
for (int i = 0; i < NUM_SLICE; i++)
{// 设置PictureBox的位置、大小等参数PictureBox imgb = new PictureBox();imgb.Left = 0;imgb.Top = i * h / NUM_SLICE;imgb.Width = w;imgb.Height = h / NUM_SLICE + 1;imgb.SizeMode = PictureBoxSizeMode.StretchImage;imgb.Visible = true;// 添加到面板panel_imgs上imgbox[i] = imgb;                panel_imgs.Controls.Add(imgbox[i]);
}

接下来需要为每个切片创建一个接收线程

for (int i = 0; i < NUM_SLICE; i++)
{new Thread(new ParameterizedThreadStart(ImgReceive)){IsBackground = true}.Start(8000 + i * 10); // 输入参数为端口号,依次增加
}

最后就是接收线程的入口函数ImgReceive的内容

private void ImgReceive(object arg)
{// 网络端口号int port = (int)arg;int index = port % 8000 / 10;// 创建套接字udpServer[index] = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);// 绑定IP和端口udpServer[index].Bind(new IPEndPoint(IPAddress.Parse(cbb_remoteIP.Text), port));// 开启数据接收线程while (true){EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);// 设置一个64k的字节数组作为缓存byte[] data = new byte[65536];int length = udpServer[index].ReceiveFrom(data, ref remoteEndPoint);//此方法把数据来源ip、port放到第二个参数中MemoryStream ms = new MemoryStream(data, 0, length);// 将图像显示到对应的PictureBox控件上Image img = Image.FromStream(ms);imgbox[index].Image = img;}
}

测试结果

测试时发送端和接收端都在同一台PC上运行,运行流程与结果如这张GIF所示,左边是发送端,右边是接收端

运行流程中的TCP创建与连接的程序本文没有给出,可以参考上一篇文章。
如果有时间的话,就继续添加利用时间戳计算延迟的程序。另外,发送端的并行处理效率有待提高,后续可以使用C++进行openMP加速看看效果。
完整项目在这里https://download.csdn.net/download/qq_42688495/12416877(资源里没有视频文件,使用时将视频放到\ImgTransmitPlus\ImgTransmitPlus\video中,再更改发送端代码中的视频文件名即可)

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

UDP实时图像传输进阶篇——1080P视频传输相关推荐

  1. 视频教程-C语言程序设计--进阶篇教学视频-C/C++

    C语言程序设计--进阶篇教学视频 烟台大学计算机学院教师,二十年余教师生涯,看出了在错综复杂的教育环境中,坚持教育教学的价值与前景.和学生并肩,与不良学风作斗争,为IT菜鸟建跑道,让大一的孩子会编程, ...

  2. Android设备实时音视频传输有效方案

    /   今日科技快讯   / 6月2日晚上8点,鸿蒙线上发布会在万众瞩目中准时开始.华为正式发布了HarmonyOS 2(以下简称鸿蒙系统),以及多款新的硬件产品,包括HUAWEI Mate 40系列 ...

  3. OpenCV进阶篇视频

    OpenCV进阶篇01 第14章 视频处理 OpenCV不仅能够处理图像,还能够处理视频.视频是由大量的图像构成的,这些图像以固定的时间间隔从视频中获取.这样,就能够使用图像处理的方法对这些图像进行处 ...

  4. QOS FEC NACK 实时音视频传输库测试报告(声网、腾讯实时音视频测试)

                        目录 QOS-FEC-NACK传输库简介 实验环境 测试DEMO说明 测试项说明 测试结果 竞品分析 总结                     QOS FE ...

  5. IoT 设备高质量的实时音视频传输解决方案

    12月10日,实时互动云服务开创者及引领者声网Agora在北京举办了媒体沟通会,发布了首款定义轻互动直播场景的"极速直播"与可降低50%直播带宽成本的"低码高清" ...

  6. 如何使用usb_cam和image_transport_plugins插件进行usb摄像头的视频获取和实时图像传输

    如何使用usb_cam和image_transport_plugins插件进行usb摄像头的视频获取和实时图像传输 前言 一.使用usb_cam驱动进行usb摄像头的图像获取 二.使用image_tr ...

  7. 从零搭建树莓派远程监控小车,udp视频传输,qt上位机

    目录 前言 一.材料准备 二.连线方式 三.软件编程 软件编程主要有一下几个方面 (1)树莓派视频传输 (2)esp8266代码 (3)上位机编程 四.总结 前言 最近刚准备完期末机器人驱动的课设,本 ...

  8. Android 手机采集摄像头视频 socket 视频传输实时传播

    这里搜集了两种实现Android 手机采集摄像头视频 socket 视频传输实时传播的方法,两种都可以使用. 第一种如下: 1.通过客户端socket请求,服务端接受到请求后,获取socket的输出流 ...

  9. UG/NX10二次开发学习视频目录整理(NXOPEN进阶篇)

    为了方便搜索需要的视频资料,整理了唐康林老师发布在B站的视频目录,支持全局目录搜索,点击直达视频. NX10二次开发(NXOPEN进阶篇) P1第01章-01-打算学习本门课程先看看这讲 P2第01章 ...

  10. 树莓派+android things+实时音视频传输demo之遥控小车

    做了个测试小车,上面安装了摄像头,通过外网进行视频传输: https://www.bilibili.com/video/av23817880/ 转载于:https://www.cnblogs.com/ ...

最新文章

  1. 中汽创智科技首席人工智能官丁华杰:AI赋能自动驾驶的几点思考
  2. 浅析网站域名申请注册的四种常见方式
  3. tensorflow2.0支持的python版本-TensorFlow 版本兼容性
  4. 【Github教程】史上最全github用法:github入门到精通
  5. CSDN中最全python字典和实例,让你轻松掌握
  6. 华为效仿苹果卖高价手机?滴滴顺风车开放灰度测试;苹果官微被投诉“攻陷”| 极客头条...
  7. 循迹小车程序编程_电子编程?其实很容易!
  8. Excel怎么快速制作二维码并保存本地?
  9. GPS卫星星历与历书
  10. Informatic中如何设置每月初,和每周五、周六跑批
  11. Dialog顶部空白点击后无法关闭Dialog
  12. IDA 中怎么查看函数的调用关系
  13. angular烂笔头
  14. ASEMI肖特基二极管MBR10200CT参数,MBR10200CT封装
  15. AH463全极高灵敏低功耗霍尔开关
  16. 无法卸载程序怎么办?
  17. 月亮的脸偷偷地在改变
  18. 提高记忆力的 10 种记忆技巧和工具
  19. libvlc media player in C# (part 2)
  20. 特福莱汽车美容是中国汽车服务行业里的一面旗帜

热门文章

  1. 怎么屏蔽计算机集成声卡,win10系统主板集成声卡关闭的设置方案
  2. 三种计算机控制系统是,计算机控制系统3
  3. 区块链游戏——开发平台总览:EOSIO
  4. “快手极速版”的模拟器多开方法
  5. LinuxI/O多路转接
  6. HTML+CSS淘宝首页[web课设代码+模块说明+效果图]
  7. Bootstrap vs Foundation vs Bulma vs Semantic vs UIkit
  8. 风变编程-python(基础语法-第1关)
  9. 一些Camera相关概念整理
  10. php 正则车架号,js 正则校验车架号VIN