如何在Pygame曲面中实施洪水填充 [英] How to implement flood fill in a Pygame surface

查看:69
本文介绍了如何在Pygame曲面中实施洪水填充的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道一种填充Pygame表面部分的好方法. 我想要的最好的例子是油漆桶在MS Paint中的工作方式.

I would like to know a good way of filling part of a Pygame surface. The best example of what I want is the way the paint bucket works in MS Paint.

例如,如果在白色表面上有一个用黑色绘制的圆,我想在圆内填充白色(或任何形状).

For example, if there were a circle drawn in black on a white surface, I want to fill the white inside the circle(or whatever the shape might be).

为了让您对自己的工作有所了解,我正在制作像素艺术工具,并且正在使用类似于MS Paint的存储桶的功能. (观看: http://imgur.com/a/ogtPV )

To give you an idea of what I'm working on, I'm making a pixel art tool and I'm working on a feature similar to the bucket from MS Paint. (Watch This: http://imgur.com/a/ogtPV)

我尝试使用Surface.get_at()Surface.set_at()一堆来填充,但是一旦获得约100x100像素的区域填充,它就会滞后太多.

I've tried using Surface.get_at() and Surface.set_at() a bunch to fill, but once you get around 100x100 pixels of an area to fill, it lags too much.

我也愿意接受其他任何不落后的方法.

I'm also open to any other methods of doing it that don't lag.

推荐答案

我发现一种方法,对于100x100区域,该方法大致花费60 ms;对于1000x1000区域,其方法在2000 ms之下.代码中的解释.

I found a method that takes roughly 60 ms for a 100x100 area, and under 2000 ms for a 1000x1000 area. Explanation in the code.

import random
import pygame
pygame.init()

screen = pygame.display.set_mode((1024, 640))
clock = pygame.time.Clock()

image = pygame.image.load('delete_image.png').convert()


def fill(surface, position, fill_color):
    fill_color = surface.map_rgb(fill_color)  # Convert the color to mapped integer value.
    surf_array = pygame.surfarray.pixels2d(surface)  # Create an array from the surface.
    current_color = surf_array[position]  # Get the mapped integer color value.

    # 'frontier' is a list where we put the pixels that's we haven't checked. Imagine that we first check one pixel and 
    # then expand like rings on the water. 'frontier' are the pixels on the edge of the pool of pixels we have checked.
    #
    # During each loop we get the position of a pixel. If that pixel contains the same color as the ones we've checked
    # we paint it with our 'fill_color' and put all its neighbours into the 'frontier' list. If not, we check the next
    # one in our list, until it's empty.

    frontier = [position]
    while len(frontier) > 0:
        x, y = frontier.pop()
        try:  # Add a try-except block in case the position is outside the surface.
            if surf_array[x, y] != current_color:
                continue
        except IndexError:
            continue
        surf_array[x, y] = fill_color
        # Then we append the neighbours of the pixel in the current position to our 'frontier' list.
        frontier.append((x + 1, y))  # Right.
        frontier.append((x - 1, y))  # Left.
        frontier.append((x, y + 1))  # Down.
        frontier.append((x, y - 1))  # Up.

    pygame.surfarray.blit_array(surface, surf_array)


while True:
    clock.tick(30)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                color = random.choice(tuple(pygame.color.THECOLORS.values()))
                print('Running')
                time = pygame.time.get_ticks()
                fill(image, event.pos, color)
                print('Finished in {} ms'.format(pygame.time.get_ticks() - time))

    screen.blit(image, (0, 0))
    pygame.display.update()

这是我尝试过的图片(如果您尝试出售图片,我会收取收益):

Here is the image I experimented with (I'll take revenue if you try to sell the image):

这篇关于如何在Pygame曲面中实施洪水填充的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆