首页 > 解决方案 > 如何在pyglet中使用原始像素数据来改变图像大小

问题描述

在将图像加载到精灵之前,我需要能够更改图像的宽度或高度。我目前正在使用 numpy 来获取中心行或列,并继续将其插入图像中,直到它的大小正确为止。我不知道这段代码是否还有效,因为我也无法将 raw_image 加载回精灵并显示它。

def set_image_size(img, x, y):
    raw_img = img.get_image_data()
    format = 'RGBA'
    pitch = raw_img.width * len(format)
    rgba = np.array(list(img.get_image_data().get_data(format, pitch))).reshape(-1, raw_img.width, len(format))
    
    mid_y = rgba[round(raw_img.height/2),:] # This is needed to stretch along Y
    while rgba.shape[0] < y:
        rgba = np.insert(rgba, round(raw_img.height/2), mid_y, 0)
    mid_x = rgba[:,round(raw_img.width/2)] # This is needed to stretch along X
    while rgba.shape[1] < x:
        rgba = np.insert(rgba, round(raw_img.width/2), mid_x, 1)
    
    raw_img.set_data(format, pitch, ''.join(map(chr, rgba.tostring())))

    return raw_img

当我尝试将其粘贴到抽象图像上并将其粘贴到屏幕上时,我得到了一个奇怪的红色条纹版本的图像。我不需要太担心质量,我只想“拉伸/平铺”图像的内部,这样边缘就不会变形。此外,我的图像非常小,只有 15 x 15 像素左右。

我该如何解决这些问题?

编辑:

当我使用 sprite.scale 时,它​​会以奇怪的方式拉伸:

self.sprite = pyglet.sprite.Sprite(self.image, self.x, self.y, batch=batch)
self.sprite.scale_x = self.width / 16

原始雪碧: 原始雪碧

拉伸(使用 sprite.scale):

在此处输入图像描述

这对这个精灵来说不是什么大问题,因为我可以使用 OpenGL Quads 来绘制它,但是我需要开始使用需要以上述方式缩放的更复杂的精灵。

标签: pythonopenglpyglet

解决方案


因此,问题在于您最初使用的图像分辨率的比例,即16px宽且7px高。默认情况下,放大图像不会像您期望的那样做任何巧妙的邻域插值和“填充空白”。

为了解决这个问题,你可以告诉 OpenGL 放大图像中的每个新像素都应该从它的邻居那里获取“灵感”。每次渲染精灵时,您可以通过在渲染循环中添加以下内容来做到这一点:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

在您需要添加过滤器的精灵的每次渲染之前调用它是很重要的。不确定技术术语是什么,但必须设置每个渲染序列,因为下次循环渲染函数时它会重置。我敢肯定,这有一个花哨的词。

这是一个工作示例:

from pyglet import *
from pyglet.gl import *

key = pyglet.window.key

class main(pyglet.window.Window):
    def __init__ (self, width=800, height=600, fps=False, *args, **kwargs):
        super(main, self).__init__(width, height, *args, **kwargs)
        self.x, self.y = 0, 0
        glEnable(GL_TEXTURE_2D) # Strictly speaking not needed, I think this is default or won't affect this test image in any significant way.

        self.keys = {}

        self.mouse_x = 0
        self.mouse_y = 0

        # The image itself is 800x400 originally
        # Positioned at x=0 and y=50 will place it at the bottom essentially
        self.sprite = pyglet.sprite.Sprite(pyglet.image.load('test.png'), 50, 50, batch=None)
        self.sprite.scale = 20 # Scale the height, not the width

        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def on_mouse_motion(self, x, y, dx, dy):
        self.mouse_x = x

    def on_key_release(self, symbol, modifiers):
        try:
            del self.keys[symbol]
        except:
            pass

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ESCAPE: # [ESC]
            self.alive = 0

        self.keys[symbol] = True

    def render(self):
        self.clear()

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) 
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        self.sprite.draw()

        self.flip()

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze
            #
            event = self.dispatch_events()

if __name__ == '__main__':
    x = main()
    x.run()

这是您可以使用的测试图像: (<-- 白色小方块,未放大效果)在此处输入图像描述

结果如下:

在此处输入图像描述


推荐阅读