前言
大概思路是Godot图片转字节数组,通过socket发送给python端,由python的opencv对字节数组转图片进行图像处理,传回Godot端。
遇到的问题:socket发送大图会比较慢,也许可以尝试共享内存的方式。
核心知识
新建一个TextureRect
func demo():
"""字节数组转Image的实例"""
var array = PoolByteArray()
for i in 64*64:
array.push_back(255)
array.push_back(0)
array.push_back(0)
array.push_back(255)
var image = Image.new()
image.create_from_data(64,64,false,5,array)
self.texture = ImageTexture.new()
self.texture.create_from_image(image)
这个实例告诉我们,ImageTexture 到 Image 到 PoolByteArray的过程
如果需要图片转字节数组只需要tex.get_data().get_data()即可
Socket部分
var client = StreamPeerTCP.new()
var thread = Thread.new()
func _ready():
client.connect_to_host('192.168.31.70',5000)
if client.is_connected_to_host():
thread.start(self,'revice')
client.put_data('你好'.to_utf8())
func revice(_all):
while true:
var rev_num = client.get_available_bytes()
if rev_num > 0:
print(rev_num)
client.get_utf8_string()
continue
elif rev_num == -1:
break
准备发送图片数据
var size = Array()
size.append(self.texture.get_data().get_size().x)
size.append(self.texture.get_data().get_size().y)
var dict = {
"heard": "图片",
"size":size,
"data":Array(self.texture.get_data().get_data())
}
# 将字典转换为JSON字符串
var json_string = JSON.print(dict)
# 将JSON字符串转换为字节数组
var json_bytes = json_string.to_utf8()
client.put_data(json_bytes)
其中字节数组不能直接填入JSON中,会导致数据损坏,所以我转成了Array数组,到python端以后直接会被解析为列表。
准备接收图片数据
var rev_num = client.get_available_bytes()
if rev_num > 0:
print(rev_num)
var data = client.get_data(rev_num)
var array = PoolByteArray(data[1])
var image = Image.new()
var size = self.texture.get_data().get_size()
image.create_from_data(size.x,size.y,false,5,array)
self.texture = ImageTexture.new()
self.texture.create_from_image(image)
这段代码主要借鉴思路,其实client如果接受到的数据很大,会分批接收,所以如果遇到分批情况这样写就会报错,需要把每批次的数据合并到一起才能转为Image
Python端代码
import socket
import threading
import json
import numpy as np
import cv2
HOST = '' # 监听所有可用的接口
PORT = 5000 # 监听的端口号
IMAGE = None
IMAGE_SIZE = []
def handle_client(conn, addr):
# 处理客户端连接
print(f'连接 {addr}')
with conn:
buffer = b''
while True:
# 检查连接是否还处于活动状态
try:
# 接收客户端发送的数据
data = conn.recv(1024)
buffer += data
if len(data) < 1024 and len(data) > 0:
# 将JSON字节数组解码为Python对象
json_string = buffer.decode('utf-8')
data = json.loads(json_string)
if data["heard"] == "图片":
IMAGE = data["data"]
IMAGE_SIZE = data["size"]
print(IMAGE_SIZE)
if data["heard"] == "进度":
jindu = data["data"]
my_array = np.array(IMAGE)
# 改变数组维度为4x3
new_arr = my_array.reshape((IMAGE_SIZE[0], IMAGE_SIZE[1], 4))
new_arr = new_arr.astype('uint8')
# 将图像数组转换为OpenCV图像格式
img = cv2.cvtColor(new_arr, cv2.COLOR_RGBA2BGRA)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Canny边缘检测
edges = cv2.Canny(gray, 100, 200)
# 执行描边
contours, hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0, 255, 255,255), jindu)
img_rgba = cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA)
img_np = np.array(img_rgba)
conn.sendall(img_np)
# 显示图像
#cv2.imwrite('output.png', img)
#cv2.imshow('image', img)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
buffer = b''
except ConnectionResetError:
print(f'客户 {addr} 断开连接')
break
#print(f'收到客户: {data.decode()}')
# 发送响应数据给客户端
#message = '你好服务器!'
#conn.sendall(message.encode())
print(f'连接已关闭 {addr}')
# 创建一个TCP套接字
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# 将套接字绑定到指定的地址和端口
s.bind((HOST, PORT))
# 监听来自客户端的连接
s.listen()
print(f'服务器监听端口 {PORT}...')
while True:
# 接受客户端连接请求
conn, addr = s.accept()
# 使用新线程处理客户端连接
threading.Thread(target=handle_client, args=(conn, addr)).start()
代码运行可能会出现问题,推荐有A通道的png图片,即RGBA8
并且图片不能过大,否则会遇到上述分批问题,所以还需要进行改进