touilleMan / godot-python

Python support for Godot 🐍🐍🐍
Other
1.83k stars 136 forks source link

Best way to display the texture produced in python on a spatial material #371

Open TheBricktop opened 1 year ago

TheBricktop commented 1 year ago

Im trying to do a simple camera feed on a quad but im missing something when it comes to handling the textures in the python script :

  from godot import exposed, export
  from godot import *
  import ctypes 
  import subprocess
  import sys
  import cv2
  import depthai as dai
  import numpy as np

  @exposed
   class Main(Spatial):
    # member variables here, example:
material = export (SpatialMaterial)
texture = None
def frame_to_godot_image(self, frame):
    image = Image()
    height, width, channels = frame.shape
    print(width, height)
    size = width * height * 3

    pool_array = PoolByteArray()
    pool_array.resize(size)

    with pool_array.raw_access() as ptr:
        numpy_array = np.ctypeslib.as_array(ctypes.cast(ptr.get_address(), ctypes.POINTER(ctypes.c_uint8)), (size,))
        numpy_array[:] = np.frombuffer(frame, dtype=np.uint8).reshape(height,width,channels).flatten()

    image.create_from_data(height, width, False, Image.FORMAT_RGB8, pool_array)
    return image
vid = cv2.VideoCapture(0)
image = None

def _ready(self):
    print("YEllo")
    #if self.material is not None:
    #   self.material.albedo_texture = self.texture

def _process(self,delta):
    ret, frame = self.vid.read()
    image = self.frame_to_godot_image(frame)
    #self.texture = image
    self.material.albedo_texture = image

` im getting no errors but the image is not showing on the quad in fron of the camera.

TheBricktop commented 1 year ago

okay after some tinkering ive got some results current code

from godot import exposed, export
from godot import *
import ctypes 
import subprocess
import sys
import cv2
import depthai as dai
import numpy as np

@exposed
class Main(Spatial):
# member variables here, example:
material = export (SpatialMaterial)
texture = ImageTexture()
def frame_to_godot_image(self, frame):
    height, width, channels = frame.shape

    print(width, height, channels)
    image = Image()
    size = width * height * channels

    pool_array = PoolByteArray()
    pool_array.resize(size)

    with pool_array.raw_access() as ptr:
        numpy_array = np.ctypeslib.as_array(ctypes.cast(ptr.get_address(), ctypes.POINTER(ctypes.c_uint8)), (size,))
        numpy_array[:] = np.frombuffer(frame, dtype=np.uint8).reshape(channels,height,width).flatten()

    image.create_from_data(height, width, False, Image.FORMAT_RGB8, pool_array)
    return image
vid = cv2.VideoCapture(0)

def _ready(self):
    print("YEllo")
    #if self.material is not None:
    #   self.material.albedo_texture = self.texture

def _process(self,delta):
    ret, bgr = self.vid.read()
    frame = cv2.cvtColor(bgr, cv2.COLOR_YUV2RGB)
    image = self.frame_to_godot_image(frame)
    self.texture.create_from_image(image) 
    self.material.albedo_texture = self.texture

but now im getting interlaced image with shift to green

obraz

ive tried bgr to rgb and various formats but none is changing for the better

Zireael07 commented 1 year ago

check material and mesh settings: is HDR on? is mirror/repeat on?

Zireael07 commented 1 year ago

Also IIRC opencv uses some weird format/color ordering, IIRC it's not RGB but YCK or something (yes, not even the standard CMYK)

TheBricktop commented 1 year ago

well that helped :

from godot import exposed, export
from godot import *
import ctypes 
import subprocess
import sys
import cv2
import numpy as np

  @exposed
  class Main(Spatial):
  # member variables here, example:
material = export (SpatialMaterial)
texture = ImageTexture()

vid = cv2.VideoCapture(0)
pool_array = PoolByteArray()

frame, height, width, channels, size = None,None,None,None,None

def frame_to_godot_image(self, frame, height, width, channels, size):
    print(width, height, channels)
    image = Image()

    with self.pool_array.raw_access() as ptr:
        numpy_array = np.ctypeslib.as_array(ctypes.cast(ptr.get_address(), ctypes.POINTER(ctypes.c_uint8)), (size,))
        numpy_array[:] = np.frombuffer(frame, dtype=np.uint8).reshape((height,width)[::-1]+(channels,)).flatten()

    image.create_from_data( width, height, False, Image.FORMAT_RGB8, self.pool_array)
    return image

def _ready(self):
    print("YEllo")
    ret, frame = self.vid.read()
    self.height, self.width, self.channels = frame.shape
    self.size = self.width * self.height * self.channels
    self.pool_array.resize(self.size)
    #if self.material is not None:
    #   self.material.albedo_texture = self.texture

def _process(self,delta):
    ret, frame = self.vid.read()
    image = self.frame_to_godot_image(frame,self.height, self.width, self.channels, self.size)
    self.texture.create_from_image(image) 
    self.material.emission_texture = self.texture

ive simply switched the height and width variables around