Я хочу спросить о том, почему возникает эта ошибка. Во-первых, позвольте мне показать вам симптом моего проекта <- .gif файл загружен по этой ссылке. </p>
Я реализовал этот проект с Python сервером TCP и клиентом Unity. Когда вы смотрите этот файл .gif, Unity отображает изображение глубины потоковой передачи с сервера Python. Хотя Unity, кажется, показывает поток изображений в режиме реального времени, он также часто показывает «метку запроса».
Я слышал, что этот знак запроса отображается всякий раз, когда единице Texture2D
не удается получить данные, но даже я добавил флаг, чтобы проверить, загружается ли изображение true
или false
, оно всегда true
. Кроме того, когда вы видите консоль Unity, она также показывает, что есть некоторые потерянные байты по сравнению с консолью python (черная консоль для python).
Я уже тестировал этот TCP-сервер, который хорошо работает с python клиентом (этот код также загружен выше по ссылке). Итак, я предположил, что это проблема Unity, но я не знаю подробно и хочу знать, как это исправить.
Это мой Python TCP-сервер:
mport pyrealsense2 as d435
import socketserver
import socket
import cv2
import numpy as np
from queue import Queue
from _thread import *
# _Set queue
enclosure_queue = Queue()
# _Configures of depth and color streams
pipeline = d435.pipeline()
config = d435.config()
config.enable_stream(d435.stream.depth, 640, 480, d435.format.z16, 30)
config.enable_stream(d435.stream.color, 640, 480, d435.format.bgr8, 30)
# _ D435 process
def D435(queue):
print("D435 processing", end="\n ")
pipeline.start(config) # _Start streaming
try:
while True:
# _Wait for a coherent pair of frames: depth and color
frames = pipeline.wait_for_frames()
depth_frame, color_frame = (frames.get_depth_frame(), frames.get_color_frame())
if not (depth_frame and color_frame):
print("Missing frame...", end="\n")
continue
# _Convert <pyrealsense2 frame> to <ndarray>
depth_image = np.asanyarray(depth_frame.get_data()) # convert any array to <ndarray>
color_image = np.asanyarray(color_frame.get_data())
# _Apply colormap on depth image
# (image must be converted to 8-bit per pixel first)
depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.05), cv2.COLORMAP_BONE)
#depth_colormap = cv2.bitwise_not(depth_colormap ) # reverse image
#print("Depth map shape = ", depth_colormap.shape)
# _Encoding
target_frame = depth_colormap
#print(target_frame.shape)
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY),95] # 0 ~ 100 quality
#encode_param = [cv2.IMWRITE_PNG_COMPRESSION,0] # 0 ~ 9 Compressiong rate
#encode_param = [int(cv2.IMWRITE_WEBP_QUALITY),95] # 0 ~ 100 quality
result, imgencode = cv2.imencode('.jpg', target_frame, encode_param) # Encode numpy into '.jpg'
data = np.array(imgencode)
stringData = data.tostring() # Convert numpy to string
print("byte Length: ", len(stringData))
queue.put(stringData) # Put the encode in the queue stack
# __ Image show
images = np.hstack((color_image, depth_colormap)) # stack both images horizontally
cv2.namedWindow('RealSense', cv2.WINDOW_AUTOSIZE)
cv2.imshow('RealSense', images)
cv2.waitKey(1)
finally:
cv2.destroyAllWindows()
# _Stop streaming
pipeline.stop()
class MyTCPHandler(socketserver.BaseRequestHandler):
queue = enclosure_queue
stringData = str()
def handle(self):
# 'self.request' is the TCP socket connected to the client
print("A client connected by: ", self.client_address[0], ":", self.client_address[1] )
while True:
try:
# _server <- client
self.data = self.request.recv(1024).strip() # 1024 byte for header
if not self.data:
print("The client disconnected by: ", self.client_address[0], ":", self.client_address[1] )
break
# _Get data from Queue stack
MyTCPHandler.stringData = MyTCPHandler.queue.get()
# _server -> client
#print(str(len(MyTCPHandler.stringData)).ljust(16).encode()) # <str>.ljust(16) and encode <str> to <bytearray>
self.request.sendall(str(len(MyTCPHandler.stringData)).ljust(16).encode())
self.request.sendall(MyTCPHandler.stringData)
#self.request.sendall(len(MyTCPHandler.stringData).to_bytes(1024, byteorder= "big"))
#self.request.sendall(MyTCPHandler.stringData)
except ConnectionResetError as e:
print("The client disconnected by: ", self.client_address[0], ":", self.client_address[1] )
break
if __name__ == "__main__":
# _Webcam process is loaded onto subthread
start_new_thread(D435, (enclosure_queue,))
# _Server on
HOST, PORT = socket.gethostname(), 8080
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
print("****** Server started ****** ", end="\n \n")
try:
server.serve_forever()
except KeyboardInterrupt as e:
print("****** Server closed ****** ", end="\n \n" )
и скрипт Unity:
Client_unity.cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace imageStream_client
{
public class Client_unity : MonoBehaviour
{
IPHostEntry ipHostInfo;
IPAddress ipAddress; // IPv4
TcpClient client_sock;
const int PORT = 8080;
NetworkStream stream;
// Start is called before the first frame update
void Start()
{
Debug.Log("*****Unity frame started *****");
ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
ipAddress = ipHostInfo.AddressList[1];
client_sock = new TcpClient(ipAddress.ToString(), PORT);
Debug.Log("***** Client Connected to the server *****");
stream = client_sock.GetStream();
}
// Update is called once per frame
void Update()
{
//Debug.Log("**** Buffer streaming ****");
// _Client -> Server
string message = "1";
byte[] buff = Encoding.ASCII.GetBytes(message);
stream.Write(buff, 0, buff.Length); // spend the byte stream into the Stream
// _Client <- Server
byte[] recvBuf = new byte[client_sock.ReceiveBufferSize]; // total receiveBuffer size
int readBytes = stream.Read(recvBuf, 0, recvBuf.Length);
//Debug.Log($"total receiveBuffer length: {recvBuf.Length}");
Debug.Log($"Real-read byte length: {readBytes}");
// _Set display image
byte[] image = new byte[readBytes];
Buffer.BlockCopy(recvBuf, 0, image, 0, readBytes);
Viewer.instance.SetImageToDisplay(image);
//Viewer.instance.SetImageToDisplay();
}
}
}
Viewer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace imageStream_client
{
public class Viewer : MonoBehaviour
{
public RawImage rawimage;
public AspectRatioFitter fit;
#region Data
public static Viewer instance;
private byte[] imageToDisplay;
#endregion
#region Get Set
public void SetImageToDisplay(byte[] image)
{
DisplayImage(image);
//instance.imageToDisplay = image;
}
#endregion
#region API
internal static void DisplayImage(byte[] image)
{
if (image == null)
return;
if (image.Length > 0)
{
//이미지 크기 생성 이후 streaming 되는 이미지 크기에 맞게 수정 해야함
Texture2D texture = new Texture2D(640, 480);
//byte형식의 데이터를 texture2D 형식으로 읽음
bool load = texture.LoadImage(image);
if (load)
{
//이미지를 화면에 입힘(Canvas 아래 RawImage)
instance.rawimage.texture = texture as Texture;
//이미지 가로 세로 비율
instance.fit.aspectRatio = 640 / 480;
}
}
}
#endregion
// Start is called before the first frame update
void Awake()
{
instance = this;
}
// Update is called once per frame
void Update()
{
//DisplayImage(instance.imageToDisplay);
}
}
}