首页 文章

通过tcp流式传输的图像被分成3个中间缺失

提问于
浏览
0

Example of result

该项目的目标是通过tcp套接字将从python主机捕获的视频流式传输到c#客户端 .

关联python2服务器脚本:

import cv2
import numpy as np
import socket
from threading import Thread

_continue = True
def imageStreamer4():
    global _continue
    cam = cv2.VideoCapture(0)
    camSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    camSocket.bind(("",8081))
    camSocket.listen(1)
    # set flip image to false if you don't want the image to be flipped
    flipImage = True

    while _continue:
        try:
            client,address = camSocket.accept()
            print("client connected")
            ret,camImage = cam.read()
            if flipImage:
                camImage = cv2.flip(camImage,1)

            #uncomment the below code to view the webcam stream locally
            """
            cv2.imshow('image',camImage)
            if cv2.waitKey(1) == 27: 
                break  # esc to quit
            """
            byteString = bytes(cv2.imencode('.jpg', camImage)[1].tostring())
            fileSize = len(byteString)
            totalSent = 0
            client.send(str(fileSize).encode())

            sizeConfirmation = client.recv(1024)

            totalSent = 0
            while totalSent < fileSize:
                totalSent += client.send(byteString[totalSent:])

            print(str(fileSize), str(totalSent),sizeConfirmation.decode('utf-8'))

        except Exception as e:
            print(e)
            print("shutting down video stream")
            _continue = False

    print("video stream exited.")

相关的c#客户端代码:

using System.Collections;
using UnityEngine;
using System;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using UnityEngine.UI;
using System.IO;

void getVideoStream()
    {
        byte[] header; 
        int recieved;
        int fileSize;
        NetworkStream dataStream;
        MemoryStream ms;
        while (connectCam)
        {
            fileSize = 0;
            recieved = 0;
            camClient = new TcpClient(camIP, camPort);

            //get header
            dataStream = camClient.GetStream();
            while (!dataStream.DataAvailable)
            {
                //waste time
            }
            header = new byte[1024];
            dataStream.Read(header, 0, header.Length);
            fileSize = Int32.Parse(Encoding.Default.GetString(bytesReducer(header)));
            byte[] result = Encoding.ASCII.GetBytes(fileSize.ToString());

            //send response
            dataStream.Write(result, 0, result.Length);

            ms = new MemoryStream();
            while (!dataStream.DataAvailable)
            {
                //waste time
            }
            while (recieved < fileSize)
            {
                byte[] data = new byte[camClient.ReceiveBufferSize];
                recieved += dataStream.Read(data, 0, data.Length);
                ms.Write(data, 0, data.Length);

            }
            //the below class simply sends function calls from secondary thread back to the main thread
            UnityMainThreadDispatcher.Instance().Enqueue(convertBytesToTexture(ms.ToArray()));
            dataStream.Close();
            camClient.Close();

        }
    }

void convertBytesToTexture(byte[] byteArray) {
        try
        {
            camTexture.LoadImage(byteArray); //Texture2D object
            camImage.texture = camTexture; //RawImage object
        }
        catch (Exception e)
        {
            print(e);
        }
    }

发送和接收的字节数与它们应该匹配 . 我不熟悉使用套接字,但我很确定数据是完整无缺的 . 不幸的是,我真的不知道为什么图像会像现在这样分裂 . (如上图所示)如果它完全相关,则服务器和客户端功能都在各自独立的线程上运行 .

我在不同的主机和客户端上运行脚本,结果保持不变 . 如果需要任何不同的信息来帮助,请问 . 我很乐意根据需要更新 .

2 回答

  • 1

    通过删除以下代码插入的空白区域,我能够正确地将图片放在一起:

    while (recieved < fileSize)
    {
         byte[] data = new byte[camClient.ReceiveBufferSize];
         recieved += dataStream.Read(data, 0, data.Length);
         ms.Write(data, 0, data.Length);
    
    }
    

    用这个替换它:

    int increment = 0;
    while (recieved < fileSize)
    {
         byte[] data = new byte[camClient.ReceiveBufferSize];
         increment = dataStream.Read(data, 0, data.Length);
         recieved += increment; 
         ms.Write(data.Take(increment).ToArray(), 0, increment);
    
    }
    

    因此,不是将客户端缓冲区的大小数组带入内存流(即使它未满),而是将其浓缩为仅通过read方法接收的信息量 . 这有效地移除了接收图像中的所有空白区域 .

  • 0

    因为Tcp是一个流,所以你应该将它视为一个字节流,所以你应该应用一些机制来识别每个图像,这样你就可以应用:

    • A delimiter :使用一组字节来分隔每个图像(但此字节集不得在流中重复),例如:

    1-发送图像字节2发送分隔符

    在客户端,您开始阅读,直到达到分隔符

    • 考虑定义 protocol 并首先发送图像大小然后发送图像数据,例如:

    1 - 前8个字节总是图像大小2-然后是图像字节

    当您首先在客户端上读取数据时,您总是读取8个字节,然后根据此大小读取其余数据 .

    • 另一种方法是使用固定大小的数据(在这种情况下对你来说有点困难)你在服务器中得到一个修复大小字节数组,如果图像数据小于字节数组,则用零填充它并在客户端上始终读取与服务器阵列大小一样多的字节数 .

    服务器发送字节[2048]和客户端读取,直到引用的字节达到2048

相关问题