Numpy array to and from ModernGL buffer (open and save with cv2)
Numpy array to and from ModernGL buffer (open and save with cv2)
我想:
- 通过 cv2 从图像 打开纹理,而不是通过 ModernGL 的
load_texture_2d
方法。
- 保存生成的图像(在
write
方法中)通过 cv2 而不是 Pillow。
我目前有以下代码:
from pathlib import Path
from array import array
import cv2
import numpy as np
from PIL import Image
import moderngl
import moderngl_window
class ImageProcessing(moderngl_window.WindowConfig):
window_size = 3840 // 2, 2160 // 2
resource_dir = Path(__file__).parent.resolve()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.image_processing = ImageTransformer(self.ctx, self.window_size)
# Not working:
#img = cv2.imread("test6.png")
#self.texture = img.astype('f4')
self.texture = self.load_texture_2d("test6.png")
def render(self, time, frame_time):
# View in Window
self.image_processing.render(self.texture, target=self.ctx.screen)
# Headless
self.image_processing.render(self.texture)
self.image_processing.write("output.png")
class ImageTransformer:
def __init__(self, ctx, size, program=None):
self.ctx = ctx
self.size = size
self.program = None
self.fbo = self.ctx.framebuffer(
color_attachments=[self.ctx.texture(self.size, 4)]
)
# Create some default program if needed
if not program:
self.program = self.ctx.program(
vertex_shader="""
#version 330
in vec2 in_position;
in vec2 in_uv;
out vec2 uv;
void main() {
gl_Position = vec4(in_position, 0.0, 1.0);
uv = in_uv;
}
""",
fragment_shader = """
#version 330
uniform sampler2D image;
in vec2 uv;
out vec4 out_color;
void main() {
vec4 color = texture(image, uv);
// do something with color here
out_color = vec4(color.r, 0, 0, color.a);
}
""",
)
# Fullscreen quad in NDC
self.vertices = self.ctx.buffer(
array(
'f',
[
# Triangle strip creating a fullscreen quad
# x, y, u, v
-1, 1, 0, 1, # upper left
-1, -1, 0, 0, # lower left
1, 1, 1, 1, # upper right
1, -1, 1, 0, # lower right
]
)
)
self.quad = self.ctx.vertex_array(
self.program,
[
(self.vertices, '2f 2f', 'in_position', 'in_uv'),
]
)
def render(self, texture, target=None):
if target:
target.use()
else:
self.fbo.use()
texture.use(0)
self.quad.render(mode=moderngl.TRIANGLE_STRIP)
def write(self, name):
# This doesn't work:
raw = self.fbo.read(components=4, dtype='f4')
buf = np.frombuffer(raw, dtype='f4')
cv2.imwrite("OUTPUT_IMAGE.png", buf)
# But this does:
## image = Image.frombytes("RGBA", self.fbo.size, self.fbo.read())
## image = image.transpose(Image.FLIP_TOP_BOTTOM)
## image.save(name, format="png")
if __name__ == "__main__":
ImageProcessing.run()
目前,当代码按原样 运行 时,不会保存任何图像。 window 只是挂起,没有任何反应。我不确定是我的代码有问题还是数据类型有误。
pillow 代码(如果您取消注释)可以保存它,但请注意:虽然我可以从 Pillow 转换为 numpy 数组,但我不想在我的用例中这样做。
澄清:window 加载和显示图像结果很好,但在 write
方法中没有正确保存。
你能说出,在 write() 方法中,buf.shape 是什么吗?我认为此时它是一个一维数组,它可能是 height * width * 4 个元素长。
imwrite() 需要它的形状正确。在 imwrite() 之前试试这个:
buf.shape = (self.size[1], self.size[0], 4)
应该将数据重塑为 (height, width, 4) 然后 imwrite() 应该接受它。
您的应用程序中缺少 som 代码
方法load_texture_2d
creates a moderngl.Texture
对象。因此,该方法加载文件,创建纹理对象并将纹理图像从 CPU 加载到 GPU。
cv2.imread
just load the image file to a NumPy array, but it doesn't create a moderngl.Texture
对象。
您必须从 NumPy 数组生成一个 moderngl.Texture
对象:
img = cv2.imread("test6.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # optional
img = np.flip(img, 0).copy(order='C') # optional
self.texture = self.ctx.texture(img.shape[1::-1], img.shape[2], img)
在将缓冲区写入图像之前,您必须根据图像格式reshape
NumPy 数组。例如:
raw = self.fbo.read(components=4, dtype='f1')
buf = np.frombuffer(raw, dtype='uint8').reshape((*self.fbo.size[1::-1], 4))
cv2.imwrite("OUTPUT_IMAGE.png", buf)
我想:
- 通过 cv2 从图像 打开纹理,而不是通过 ModernGL 的
load_texture_2d
方法。 - 保存生成的图像(在
write
方法中)通过 cv2 而不是 Pillow。
我目前有以下代码:
from pathlib import Path
from array import array
import cv2
import numpy as np
from PIL import Image
import moderngl
import moderngl_window
class ImageProcessing(moderngl_window.WindowConfig):
window_size = 3840 // 2, 2160 // 2
resource_dir = Path(__file__).parent.resolve()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.image_processing = ImageTransformer(self.ctx, self.window_size)
# Not working:
#img = cv2.imread("test6.png")
#self.texture = img.astype('f4')
self.texture = self.load_texture_2d("test6.png")
def render(self, time, frame_time):
# View in Window
self.image_processing.render(self.texture, target=self.ctx.screen)
# Headless
self.image_processing.render(self.texture)
self.image_processing.write("output.png")
class ImageTransformer:
def __init__(self, ctx, size, program=None):
self.ctx = ctx
self.size = size
self.program = None
self.fbo = self.ctx.framebuffer(
color_attachments=[self.ctx.texture(self.size, 4)]
)
# Create some default program if needed
if not program:
self.program = self.ctx.program(
vertex_shader="""
#version 330
in vec2 in_position;
in vec2 in_uv;
out vec2 uv;
void main() {
gl_Position = vec4(in_position, 0.0, 1.0);
uv = in_uv;
}
""",
fragment_shader = """
#version 330
uniform sampler2D image;
in vec2 uv;
out vec4 out_color;
void main() {
vec4 color = texture(image, uv);
// do something with color here
out_color = vec4(color.r, 0, 0, color.a);
}
""",
)
# Fullscreen quad in NDC
self.vertices = self.ctx.buffer(
array(
'f',
[
# Triangle strip creating a fullscreen quad
# x, y, u, v
-1, 1, 0, 1, # upper left
-1, -1, 0, 0, # lower left
1, 1, 1, 1, # upper right
1, -1, 1, 0, # lower right
]
)
)
self.quad = self.ctx.vertex_array(
self.program,
[
(self.vertices, '2f 2f', 'in_position', 'in_uv'),
]
)
def render(self, texture, target=None):
if target:
target.use()
else:
self.fbo.use()
texture.use(0)
self.quad.render(mode=moderngl.TRIANGLE_STRIP)
def write(self, name):
# This doesn't work:
raw = self.fbo.read(components=4, dtype='f4')
buf = np.frombuffer(raw, dtype='f4')
cv2.imwrite("OUTPUT_IMAGE.png", buf)
# But this does:
## image = Image.frombytes("RGBA", self.fbo.size, self.fbo.read())
## image = image.transpose(Image.FLIP_TOP_BOTTOM)
## image.save(name, format="png")
if __name__ == "__main__":
ImageProcessing.run()
目前,当代码按原样 运行 时,不会保存任何图像。 window 只是挂起,没有任何反应。我不确定是我的代码有问题还是数据类型有误。
pillow 代码(如果您取消注释)可以保存它,但请注意:虽然我可以从 Pillow 转换为 numpy 数组,但我不想在我的用例中这样做。
澄清:window 加载和显示图像结果很好,但在 write
方法中没有正确保存。
你能说出,在 write() 方法中,buf.shape 是什么吗?我认为此时它是一个一维数组,它可能是 height * width * 4 个元素长。
imwrite() 需要它的形状正确。在 imwrite() 之前试试这个:
buf.shape = (self.size[1], self.size[0], 4)
应该将数据重塑为 (height, width, 4) 然后 imwrite() 应该接受它。
您的应用程序中缺少 som 代码
方法load_texture_2d
creates a moderngl.Texture
对象。因此,该方法加载文件,创建纹理对象并将纹理图像从 CPU 加载到 GPU。
cv2.imread
just load the image file to a NumPy array, but it doesn't create a moderngl.Texture
对象。
您必须从 NumPy 数组生成一个 moderngl.Texture
对象:
img = cv2.imread("test6.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # optional
img = np.flip(img, 0).copy(order='C') # optional
self.texture = self.ctx.texture(img.shape[1::-1], img.shape[2], img)
在将缓冲区写入图像之前,您必须根据图像格式reshape
NumPy 数组。例如:
raw = self.fbo.read(components=4, dtype='f1')
buf = np.frombuffer(raw, dtype='uint8').reshape((*self.fbo.size[1::-1], 4))
cv2.imwrite("OUTPUT_IMAGE.png", buf)