Warm tip: This article is reproduced from serverfault.com, please click

python-往返于ModernGL缓冲区的Numpy数组(使用cv2打开并保存)

(python - Numpy array to and from ModernGL buffer (open and save with cv2))

发布于 2020-11-29 01:05:28

我要:

  1. 通过cv2而不是通过ModernGL的load_texture_2d方法从图像中打开纹理
  2. 通过cv2而不是Pillow保存结果图像(在write方法中)

我目前有以下代码:

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()

当前,按原样运行代码时,不会保存任何图像。窗户只是挂着,什么也没有发生。我不确定代码中是否有错误或数据类型是否错误。

枕头代码(如果你取消注释)可以保存它,但是请注意:虽然我可以从Pillow转换为numpy数组,但我不希望在用例中使用它。

澄清:窗口加载并显示图像结果很好,但是没有正确保存在write方法中。

Questioner
correctsyntax
Viewed
12
Rabbid76 2020-12-02 23:03:20

你的应用程序中缺少Som代码

该方法load_texture_2d创建一个moderngl.Texture对象。因此,该方法将加载文件,创建纹理对象并将纹理图像从CPU加载到GPU。

cv2.imread只需将图像文件加载到NumPy数组中,但不会创建moderngl.Texture对象。

你必须moderngl.Texture从NumPy数组生成一个对象:

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)