Godot内置PS功能

前言

大概思路是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

并且图片不能过大,否则会遇到上述分批问题,所以还需要进行改进

猜你喜欢

转载自blog.csdn.net/u012863565/article/details/130653188