2025-09-26 10:31:23 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
namespace DogAndArmControl
|
|
|
|
|
{
|
|
|
|
|
public class VideoCaltulate
|
|
|
|
|
{
|
|
|
|
|
private MemoryStream imageBuffer = new MemoryStream(); // 图像数据缓冲区
|
|
|
|
|
private byte[] videoBuffer = new byte[1400]; // 视频数据缓冲区
|
|
|
|
|
private int videoWidth;
|
|
|
|
|
private int videoHeight;
|
|
|
|
|
|
|
|
|
|
// 原有的单独视频流接收方法(保留兼容性)
|
|
|
|
|
public async Task ReceiveVideoFramesAsync(CancellationToken cancellationToken, NetworkStream videoStream, PictureBox VideoBox, bool flag)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while (!cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 接收4字节的图像大小信息
|
|
|
|
|
int sizeBufferSize = 4;
|
|
|
|
|
byte[] sizeBuffer = new byte[sizeBufferSize];
|
|
|
|
|
int totalRead = 0;
|
|
|
|
|
|
|
|
|
|
while (totalRead < sizeBufferSize && !cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
int read = await videoStream.ReadAsync(sizeBuffer, totalRead, sizeBufferSize - totalRead, cancellationToken);
|
|
|
|
|
if (read == 0) break;
|
|
|
|
|
totalRead += read;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (totalRead != sizeBufferSize || cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
throw new IOException("未接收到完整的图像大小信息");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int imageSize = BitConverter.ToInt32(sizeBuffer, 0);
|
|
|
|
|
|
|
|
|
|
if (imageSize <= 0 || imageSize > 20 * 1024 * 1024)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine($"Invalid image size: {imageSize} bytes. Skipping frame.");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 接收图像数据
|
|
|
|
|
imageBuffer.SetLength(0); // 清空缓冲区
|
|
|
|
|
int bytesRead = 0;
|
|
|
|
|
while (bytesRead < imageSize && !cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
int chunkSize = Math.Min(videoBuffer.Length, imageSize - bytesRead);
|
|
|
|
|
int read = await videoStream.ReadAsync(videoBuffer, 0, chunkSize, cancellationToken);
|
|
|
|
|
if (read == 0) break;
|
|
|
|
|
|
|
|
|
|
imageBuffer.Write(videoBuffer, 0, read);
|
|
|
|
|
bytesRead += read;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bytesRead != imageSize || cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
throw new IOException($"未接收到完整的图像数据,预期: {imageSize}, 实际: {bytesRead}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在UI线程上异步更新图像
|
|
|
|
|
await Task.Run(() => ProcessImageData(VideoBox, flag));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception) { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 新增:接收合并视频流并分割显示到两个PictureBox的方法
|
|
|
|
|
public async Task ReceiveMergedVideoFramesAsync(CancellationToken cancellationToken, NetworkStream videoStream, PictureBox dogVideoBox, PictureBox armVideoBox)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while (!cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 接收4字节的图像大小信息
|
|
|
|
|
int sizeBufferSize = 4;
|
|
|
|
|
byte[] sizeBuffer = new byte[sizeBufferSize];
|
|
|
|
|
int totalRead = 0;
|
|
|
|
|
|
|
|
|
|
while (totalRead < sizeBufferSize && !cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
int read = await videoStream.ReadAsync(sizeBuffer, totalRead, sizeBufferSize - totalRead, cancellationToken);
|
|
|
|
|
if (read == 0) break;
|
|
|
|
|
totalRead += read;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int imageSize = BitConverter.ToInt32(sizeBuffer, 0);
|
|
|
|
|
|
|
|
|
|
if (imageSize <= 0 || imageSize > 20 * 1024 * 1024)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine($"Invalid image size: {imageSize} bytes. Skipping frame.");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 接收图像数据
|
|
|
|
|
imageBuffer.SetLength(0); // 清空缓冲区
|
|
|
|
|
int bytesRead = 0;
|
|
|
|
|
while (bytesRead < imageSize && !cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
int chunkSize = Math.Min(videoBuffer.Length, imageSize - bytesRead);
|
|
|
|
|
int read = await videoStream.ReadAsync(videoBuffer, 0, chunkSize, cancellationToken);
|
|
|
|
|
if (read == 0) break;
|
|
|
|
|
|
|
|
|
|
imageBuffer.Write(videoBuffer, 0, read);
|
|
|
|
|
bytesRead += read;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bytesRead != imageSize || cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
throw new IOException($"未接收到完整的图像数据,预期: {imageSize}, 实际: {bytesRead}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理合并后的图像数据并分割显示
|
2025-10-13 16:34:23 +08:00
|
|
|
|
await Task.Run(() => ProcessMergedImageData(dogVideoBox, armVideoBox));
|
|
|
|
|
//await Task.Run(() => ProcessImageData(armVideoBox));
|
2025-09-26 10:31:23 +08:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine($"Error receiving merged video frame: {ex.Message}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine($"Error in ReceiveMergedVideoFramesAsync: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理合并后的图像数据并分割显示到两个PictureBox
|
|
|
|
|
private void ProcessMergedImageData(PictureBox dogVideoBox, PictureBox armVideoBox)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
imageBuffer.Position = 0;
|
|
|
|
|
|
|
|
|
|
using (var mergedImage = Image.FromStream(imageBuffer))
|
|
|
|
|
{
|
|
|
|
|
// 获取合并图像的尺寸
|
|
|
|
|
int mergedWidth = mergedImage.Width;
|
|
|
|
|
int mergedHeight = mergedImage.Height;
|
|
|
|
|
|
|
|
|
|
// 计算分割点(假设是横向拼接,左右各占一半)
|
|
|
|
|
int halfWidth = mergedWidth / 2;
|
|
|
|
|
|
|
|
|
|
// 创建两个分割后的图像
|
|
|
|
|
Bitmap dogImage = new Bitmap(halfWidth, mergedHeight);
|
|
|
|
|
Bitmap armImage = new Bitmap(halfWidth, mergedHeight);
|
|
|
|
|
|
|
|
|
|
using (Graphics dogGraphics = Graphics.FromImage(dogImage))
|
|
|
|
|
using (Graphics armGraphics = Graphics.FromImage(armImage))
|
|
|
|
|
{
|
|
|
|
|
// 分割左半部分给机械狗视频
|
|
|
|
|
Rectangle dogSourceRect = new Rectangle(0, 0, halfWidth, mergedHeight);
|
|
|
|
|
Rectangle dogDestRect = new Rectangle(0, 0, halfWidth, mergedHeight);
|
|
|
|
|
dogGraphics.DrawImage(mergedImage, dogDestRect, dogSourceRect, GraphicsUnit.Pixel);
|
|
|
|
|
|
|
|
|
|
// 分割右半部分给机械臂视频
|
|
|
|
|
Rectangle armSourceRect = new Rectangle(halfWidth, 0, halfWidth, mergedHeight);
|
|
|
|
|
Rectangle armDestRect = new Rectangle(0, 0, halfWidth, mergedHeight);
|
|
|
|
|
armGraphics.DrawImage(mergedImage, armDestRect, armSourceRect, GraphicsUnit.Pixel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在UI线程上更新两个PictureBox
|
|
|
|
|
UpdatePictureBox(dogVideoBox, dogImage, false);
|
|
|
|
|
UpdatePictureBox(armVideoBox, armImage, true); // 机械臂视频需要旋转180度
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine($"Error processing merged image data: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新单个PictureBox的辅助方法
|
|
|
|
|
private void UpdatePictureBox(PictureBox pictureBox, Bitmap image, bool rotateImage)
|
|
|
|
|
{
|
|
|
|
|
if (pictureBox.InvokeRequired)
|
|
|
|
|
{
|
|
|
|
|
pictureBox.BeginInvoke(new Action(() =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (pictureBox.Image != null)
|
|
|
|
|
{
|
|
|
|
|
pictureBox.Image.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bitmap displayImage = new Bitmap(image);
|
|
|
|
|
if (rotateImage)
|
|
|
|
|
{
|
|
|
|
|
displayImage.RotateFlip(RotateFlipType.Rotate180FlipNone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pictureBox.Image = displayImage;
|
|
|
|
|
pictureBox.Refresh();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine($"Error updating PictureBox: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (pictureBox.Image != null)
|
|
|
|
|
{
|
|
|
|
|
pictureBox.Image.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bitmap displayImage = new Bitmap(image);
|
|
|
|
|
if (rotateImage)
|
|
|
|
|
{
|
|
|
|
|
displayImage.RotateFlip(RotateFlipType.Rotate180FlipNone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pictureBox.Image = displayImage;
|
|
|
|
|
pictureBox.Refresh();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine($"Error updating PictureBox: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 原有的单独图像处理方法(保留兼容性)
|
|
|
|
|
public void ProcessImageData(PictureBox videoPictureBox, bool flag = false)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
imageBuffer.Position = 0;
|
|
|
|
|
|
|
|
|
|
if (videoPictureBox.InvokeRequired)
|
|
|
|
|
{
|
|
|
|
|
videoPictureBox.BeginInvoke(new Action(() =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (videoPictureBox.Image != null)
|
|
|
|
|
{
|
|
|
|
|
videoPictureBox.Image.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (var tempImage = Image.FromStream(imageBuffer))
|
|
|
|
|
{
|
|
|
|
|
// 如果需要旋转,则旋转180度
|
|
|
|
|
Bitmap displayedImage = new Bitmap(tempImage);
|
|
|
|
|
if (flag)
|
|
|
|
|
{
|
|
|
|
|
displayedImage.RotateFlip(RotateFlipType.Rotate180FlipNone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示图像
|
|
|
|
|
videoPictureBox.Image = displayedImage;
|
|
|
|
|
|
|
|
|
|
// 更新分辨率信息
|
|
|
|
|
videoWidth = displayedImage.Width;
|
|
|
|
|
videoHeight = displayedImage.Height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
videoPictureBox.Refresh();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
// Handle any exceptions (e.g., image load failure)
|
|
|
|
|
Debug.WriteLine($"Error processing image: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (videoPictureBox.Image != null)
|
|
|
|
|
{
|
|
|
|
|
videoPictureBox.Image.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (var tempImage = Image.FromStream(imageBuffer))
|
|
|
|
|
{
|
|
|
|
|
Bitmap displayedImage = new Bitmap(tempImage);
|
|
|
|
|
if (flag)
|
|
|
|
|
{
|
|
|
|
|
displayedImage.RotateFlip(RotateFlipType.Rotate180FlipNone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
videoPictureBox.Image = displayedImage;
|
|
|
|
|
|
|
|
|
|
videoWidth = displayedImage.Width;
|
|
|
|
|
videoHeight = displayedImage.Height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
videoPictureBox.Refresh();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
// Handle any exceptions (e.g., image load failure)
|
|
|
|
|
Debug.WriteLine($"Error processing image: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
// Handle any outer exceptions
|
|
|
|
|
Debug.WriteLine($"Error processing image data: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|