歌者文明清理员 发表于 2023-6-15 19:26:25

pygame.translate.rotate()

Python 的帮助文档提到,



rotate(...)
    rotate(surface, angle) -> Surface
    rotate an image

旋转一个图片
但是在实际使用 rotate() 时就有留白问题。比如我这么一张图

https://fishc.com.cn/favicon.ico

rotate 45° 后就会变成

https://t1.wodetu.cn/2023/06/15/f850352ad56da8020461e1462e4406a6.png

再次 rotate 45

https://t3.wodetu.cn/2023/06/15/845d41e5dc05bc673bdaf2bd7f7681df.png

越变越大!怎么解决啊,才能像在Word中操作一样的效果?

isdkz 发表于 2023-6-15 19:29:43

在 Pygame 中,当你旋转一个图片,会有一个所谓的"边界矩形"(bounding rectangle),该矩形围绕着旋转后的图片。因此,每次你旋转图片时,这个边界矩形都可能会变大以适应旋转后的图像,即使旋转的图像本身的大小并没有变化。这就是为什么在连续旋转图片时,图像的尺寸会变大。

要解决这个问题,你需要在旋转之前先裁剪原始图像的边界矩形,以保持图像的大小不变。这可以通过将源图像剪裁到只包含非透明像素来实现。然后,你可以在旋转后再次剪裁图像,以移除任何新添加的空白区域。

下面是一种可能的解决方法:

def trim(image):
    bg = pygame.Surface(image.get_size())
    bg = bg.convert()
    bg.fill((0,0,0))

    left = image.get_width()
    right = 0
    top = image.get_height()
    bottom = 0

    image.set_colorkey((0,0,0))
    for x in range(image.get_width()):
      for y in range(image.get_height()):
            if image.get_at((x, y)) != (0, 0, 0, 0):
                left = min(x, left)
                right = max(x, right)
                top = min(y, top)
                bottom = max(y, bottom)

    width = right - left + 1
    height = bottom - top + 1

    return image.subsurface(pygame.Rect(left, top, width, height))

def rotate(image, angle):
    return pygame.transform.rotate(trim(image), angle)


这里, trim() 函数通过移除所有的透明像素来剪裁一个图像, rotate() 函数则是先剪裁图像,然后再旋转。

需要注意的是,这种方法可能会消耗大量的处理器时间,特别是对于大图片和高帧率动画。一个可能的改进是,不要每帧都旋转图像,而是在开始时预计算一个旋转的图像序列,然后在运行时使用这些预计算的图像。

歌者文明清理员 发表于 2023-6-15 19:31:13

isdkz 发表于 2023-6-15 19:29
在 Pygame 中,当你旋转一个图片,会有一个所谓的"边界矩形"(bounding rectangle),该矩形围绕着旋转后的 ...

bg = bg.convert()
的作用是什么?我玩pygame从没用过,而且去掉也没影响
image.set_colorkey((0,0,0))
又是啥意思?

isdkz 发表于 2023-6-15 19:33:59

歌者文明清理员 发表于 2023-6-15 19:31


让我们一一来解释这两个函数的含义:

1.bg = bg.convert()

convert()是一个非常重要的 Pygame 函数,它会将图像数据转换成一个与显示表面(display surface)格式兼容的新格式。这可以显著提高图像绘制的速度。如果你没有使用convert() ,那么每次图像被绘制时,Pygame 都必须在内部将其转换成一个可以在屏幕上绘制的格式,这会降低性能。不过,如果你在某些情况下不使用convert() ,你可能也不会看到明显的性能差异,特别是在处理小图像或者不需要频繁绘制的情况下。

2.image.set_colorkey((0,0,0))

set_colorkey()是用于设置透明色的函数。你可以为图像选择一个颜色,使其在图像上绘制时变为透明。在这个例子中,颜色 (0,0,0)(即黑色)被设置为了透明色。这意味着在后续的代码中,所有黑色的像素(具有 RGB 值 (0,0,0))都会被视为透明的,不会被绘制。

这两个函数在很多情况下都很有用,但如果你的代码也可以在没有它们的情况下正常工作,那就可以不用它们。这完全取决于你的具体需求和你正在处理的特定图像。

歌者文明清理员 发表于 2023-6-15 19:42:05

isdkz 发表于 2023-6-15 19:33
让我们一一来解释这两个函数的含义:

1.bg = bg.convert()


那么什么情况需要使用 bg = bg.convert() 呢

isdkz 发表于 2023-6-15 19:44:21

歌者文明清理员 发表于 2023-6-15 19:42
那么什么情况需要使用 bg = bg.convert() 呢

bg = bg.convert()主要用于提高渲染效率,它会将 Surface 对象的像素格式转换为与屏幕的像素格式一致。通常有以下几种情况可能需要使用convert() :

1. 大型图片和/或频繁绘制的情况:对于大型图片或在每个游戏循环中都需要绘制的图片,使用convert()可以显著提高渲染速度,因为每次绘制时都不需要再进行额外的像素格式转换。

2. 从外部源加载图片:当你从文件或网络加载图片时,加载进来的图像数据可能与显示设备的像素格式不一致。在这种情况下,使用convert()函数会使绘制更加高效。

3. 修改图片数据:如果你需要直接修改图像数据(例如,通过pygame.Surface对象的get_at()或set_at()方法),则最好先将其转换为像素数据的原始格式。这样可以避免在读取或写入像素时进行额外的格式转换。

总的来说, convert()不是必须的,但在处理大型图像或需要频繁更新的图像时,它可以帮助提高 Pygame 的绘图性能。在一些低端的硬件或资源受限的环境中,这可能会有显著的影响。然而,在许多情况下,你可能不会注意到有或没有convert()的区别,特别是对于小型图像或较少更新的图像。

歌者文明清理员 发表于 2023-6-15 19:45:44

isdkz 发表于 2023-6-15 19:44
bg = bg.convert()主要用于提高渲染效率,它会将 Surface 对象的像素格式转换为与屏幕的像素格式一致 ...

那一般在哪里调用,不同地方调用有什么区别吗

歌者文明清理员 发表于 2023-6-15 19:53:03

isdkz 发表于 2023-6-15 19:29
在 Pygame 中,当你旋转一个图片,会有一个所谓的"边界矩形"(bounding rectangle),该矩形围绕着旋转后的 ...

《完美地解决了我的问题》
import pygame
pygame.init()

def trim(image):
    bg = pygame.Surface(image.get_size())
    bg = bg.convert()
    bg.fill((0,0,0))

    left = image.get_width()
    right = 0
    top = image.get_height()
    bottom = 0

    image.set_colorkey((0,0,0))
    for x in range(image.get_width()):
      for y in range(image.get_height()):
            if image.get_at((x, y)) != (0, 0, 0, 0):
                left = min(x, left)
                right = max(x, right)
                top = min(y, top)
                bottom = max(y, bottom)

    width = right - left + 1
    height = bottom - top + 1

    return image.subsurface(pygame.Rect(left, top, width, height))

def rotate(image, angle):
    return pygame.transform.rotate(trim(image), angle)


class Actor(pygame.sprite.Sprite):
    def __init__(self):
      pygame.sprite.Sprite.__init__(self)
      self.image = pygame.image.load("fishc.png")
      self.rect = self.image.get_rect()
      self.rect.center = 320, 240

size = width, height = 640, 480
screen = pygame.display.set_mode(size)
fishc = Actor()
running = True
while running:
    screen.fill((118, 215, 234))
    screen.blit(fishc.image, fishc.rect)
    fishc.image = rotate(fishc.image, 2)
    for event in pygame.event.get():
      if event.type == pygame.QUIT:
            running = False
    pygame.display.flip()
pygame.quit()

isdkz 发表于 2023-6-15 19:56:07

歌者文明清理员 发表于 2023-6-15 19:45
那一般在哪里调用,不同地方调用有什么区别吗

convert()函数通常在加载图像后立即调用,以优化图像的内部表示,使其更适合快速绘制。以下是一个典型的用法示例:

image = pygame.image.load("image.png")
image = image.convert()


你可能也会在其他地方看到convert()的使用,例如在对图像进行某种处理(如缩放或旋转)后:

image = pygame.transform.scale(image, (100, 100))
image = image.convert()


这可能有助于优化处理后的图像的性能,尤其是当你多次绘制这个处理过的图像时。但是请注意,转换可能会消耗一些时间,所以如果你立即使用处理过的图像,那么在处理后调用convert()可能并不会提高性能。

此外,请注意convert()方法会删除图像的 alpha 通道(如果有的话)。如果你的图像有 alpha 通道(即它是部分透明的),你应该使用convert_alpha()方法而不是convert() 。

总的来说,最佳的convert()调用位置取决于你的具体需求。一般来说,在加载图像后立即调用它是最常见的做法,因为这可以确保图像在首次绘制时就已经被优化。然而,在其他地方调用它可能在某些情况下有用,尤其是当你需要处理大量图像,或者需要多次绘制处理过的图像时。

歌者文明清理员 发表于 2023-6-15 20:43:47

isdkz 发表于 2023-6-15 19:56
convert()函数通常在加载图像后立即调用,以优化图像的内部表示,使其更适合快速绘制。以下是一个典型 ...

8#

isdkz 发表于 2023-6-15 20:44:38

歌者文明清理员 发表于 2023-6-15 20:43
8#

歌者文明清理员 发表于 2023-6-15 20:49:57

isdkz 发表于 2023-6-15 20:44


https://fishc.com.cn/forum.php?mod=viewthread&tid=229759&page=1#pid6260291

歌者文明清理员 发表于 2023-6-15 21:48:08

isdkz 发表于 2023-6-15 20:44


please anser

sfqxx_小 发表于 2023-6-16 22:12:22

isdkz 发表于 2023-6-15 20:44


8#他说有问题
页: [1]
查看完整版本: pygame.translate.rotate()