抗锯齿图像

Antialiasing an image

我在 pygame 中有一张图片。我想对其应用抗锯齿。我怎样才能做到这一点?理想情况下,我可以只使用 pygame 和内置模块来做到这一点,但如有必要,我愿意接受其他选择。

更具体地说,我有一张正方形分成 4 份的图像。每个象限都有不同的颜色。我想模糊它,让它看起来更像一个渐变,这样颜色不会在象限相交的地方立即切换,而是会慢慢褪色。我相信抗锯齿是实现这一目标的最佳方式?这是我的意思的图像:left: what I've got, right: what I need to have

不清楚您要使用哪种特定图像平滑算法。 SciPy 提供了一些相关的功能,因此我使用 ndimage.gaussian_filter().

构建了一个示例

单击鼠标按钮将应用过滤器,或者您可以滚动滚轮。

import pygame
from scipy.ndimage import gaussian_filter
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html


def smooooooth(screen):
    """Apply a gaussian filter to each colour plane"""
    # Get reference pixels for each colour plane and then apply filter
    r = pygame.surfarray.pixels_red(screen)
    gaussian_filter(r, sigma=72, mode="nearest", output=r)
    g = pygame.surfarray.pixels_green(screen)
    gaussian_filter(g, sigma=72, mode="nearest", output=g)
    b = pygame.surfarray.pixels_blue(screen)
    gaussian_filter(b, sigma=72, mode="nearest", output=b)

height = 300
width = 300

pygame.init()
screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
pygame.display.set_caption("Smooth Image")
clock = pygame.time.Clock()

# draw initial pattern
screen.fill((194, 198, 199))  # fill with gray
# fill top left quadrant with white
screen.fill(pygame.Color("white"), pygame.Rect(0, 0, width // 2, height // 2))
# fill bottom left quadrant with black
screen.fill(pygame.Color("black"), pygame.Rect(width // 2, height // 2, width, height))

count = 0
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONUP:
            smooooooth(screen)
            count += 1
            pygame.display.set_caption(f"Smooth Image {count}")

    pygame.display.update()
    # limit framerate
    clock.tick(30)
pygame.quit()

如果您使用 gaussian_filter 函数的 sigma 参数,您可能会更接近您所追求的目标。例如。使用 sigma 72,两遍看起来像这样:

我修改了示例代码以正确支持屏幕大小调整,这将重绘基本图案并使用 +-增加 sigma 值的键,以便您可以交互地进行。按住 Shift 调整十位而不是一位。

import pygame
from scipy.ndimage import gaussian_filter
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html

def smooooooth(screen, sisgma):
    """Apply a gaussian filter to each colour plane"""
    # Get reference pixels for each colour plane and then apply filter
    r = pygame.surfarray.pixels_red(screen)
    gaussian_filter(r, sigma=sigma, mode="nearest", output=r)
    g = pygame.surfarray.pixels_green(screen)
    gaussian_filter(g, sigma=sigma, mode="nearest", output=g)
    b = pygame.surfarray.pixels_blue(screen)
    gaussian_filter(b, sigma=sigma, mode="nearest", output=b)

def draw_grey_squares(screen):
    """Draw the base pattern"""
    screen.fill((194, 198, 199))  # fill with grey
    # fill top left quadrant with white
    screen.fill(pygame.Color("white"), (0, 0, width // 2, height // 2))
    # fill bottom left quadrant with black
    screen.fill(pygame.Color("black"), (width // 2, height // 2, width, height))

height = 300
width = 300

pygame.init()
screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
draw_grey_squares(screen)
pygame.display.set_caption("Smooth Image")
clock = pygame.time.Clock()

sigma = 72
count = 0
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.VIDEORESIZE:
            # redraw on window resize
            width, height = event.w, event.h
            draw_grey_squares(screen)
            count = 0
        elif event.type == pygame.KEYUP:
            # support + and - to modify sigma
            if event.key in (pygame.K_PLUS, pygame.K_KP_PLUS):
                if event.mod & pygame.KMOD_SHIFT:
                    sigma += 10
                else:
                    sigma += 1
            elif event.key in (pygame.K_MINUS, pygame.K_KP_MINUS):
                if event.mod & pygame.KMOD_SHIFT:
                    sigma -= 10
                else:
                    sigma -= 1
                sigma = max(sigma, 1)  # sigma below one doesn't make sense
        elif event.type == pygame.MOUSEBUTTONUP:
            smooooooth(screen, sigma)
            count += 1
    pygame.display.set_caption(f"Smooth Image {count} σ {sigma}")
    pygame.display.update()
    clock.tick(30)  # limit framerate
pygame.quit()

这里有一个 sigma 200 的例子: