所以我正在尝试创建一个泛洪填充算法,但我一直遇到递归错误。该算法似乎有无限递归,我无法确定原因。我在互联网上找了很多,但我找不到解决方案,因为根据大多数消息来源,我的程序似乎是正确的。然而,似乎出了什么问题。这是代码的编辑版本。错误消息仍然是最大重复次数。
我能得到一些帮助吗?
from PIL import Image, ImageTk
from random import *
w= 75
h= w
flood = Image.new("RGB", (w,h), (0,0,0))
x = 0
y = 0
count = 0
colorlist = []
i = 0
while x < w -1:
y = 0
while y < h-1:
r = random()
if r < .25:
flood.putpixel((x,y), (0,0,0))
else:
flood.putpixel((x,y), (255,255,255))
y += 1
x += 1
x = 0
y = 0
while x < w-1:
y = 0
while y < h-1:
r = random()
if x == 0 or y == 0 or x == w-1 or y ==h-1:
flood.putpixel((x,y), (0,0,0))
y += 1
x += 1
def floodfill(x,y, d,e,f, g,h,i, image, count):
count+=1
(a,b,c) = image.getpixel((x,y))
if (a,b,c) == (255,255,255):
(j,k,l) = image.getpixel((x-1,y))
(m,n,o) = image.getpixel((x+1, y))
(p,q,r) = image.getpixel((x,y-1))
(s,t,u) = image.getpixel((x,y+1))
if count > 990:
return
if (a,b,c) == (255,255,255):
image.putpixel((x,y), (g,h,i))
floodfill(x-1, y, d,e,f, g,h,i, image, count)
floodfill(x+1, y, d,e,f, g,h,i, image, count)
floodfill(x, y-1, d,e,f, g,h,i, image, count)
floodfill(x, y+1, d,e,f, g,h,i, image,count)
floodfill(2,2, 0,0,0,255,0,0,flood, 0)
flood.save("flood.png")
print("done")
Python有抛出maximum recursion depth exceeded
错误的倾向,即使算法不会无限递归,最终会自行停止。对此有两种解决方案:增加递归极限,或者切换到迭代算法。
使用sys.setrecursionlimit
可以提高递归限制。选择一个高于算法最坏情况下递归深度的数字。在您的情况下,这将是图像中的像素数length * height
。
将您的算法更改为迭代算法相当简单,因为只要您至少一次获得所有像素,以何种顺序绘制像素并不重要。set
非常适合保存唯一的非有序数据,所以让我们用它来存储我们需要绘制的像素。
def floodFill(x,y, d,e,f, g,h,i, image):
toFill = set()
toFill.add((x,y))
while not toFill.empty():
(x,y) = toFill.pop()
(a,b,c) == image.getpixel((x,y))
if not (a,b,c) == (255, 255, 255):
continue
image.putpixel((x,y), (g,h,i))
toFill.add((x-1,y))
toFill.add((x+1,y))
toFill.add((x,y-1))
toFill.add((x,y+1))
image.save("flood.png")
如果你确实使用迭代方法,一定要在其中放入绑定检查。否则,它可能会永远运行!或者至少在你的硬盘被一个巨大的toFill
集填满之前。
为什么不以深度优先的方式进行泛洪填充而不是递归呢?递归无论如何都使用隐式堆栈,所以不会有任何损失。
是的,正如评论中所指出的,你应该检查x和y是否越界。
这还没有经过测试,但主要基于您提供的代码。它应该起作用,并提供了一种实现floodfill
算法的替代方法。该功能可能更有效。
import PIL
import random
import collections
WHITE = 255, 255, 255
BLACK = 0, 0, 0
RED = 255, 0, 0
def main(width, height):
flood = PIL.Image.new('RGB', (width, height), BLACK)
# Create randomly generated walls
for x in range(width):
for y in range(height):
flood.putpixel((x, y), BLACK if random.random() < 0.15 else WHITE)
# Create borders
for x in range(width):
for y in range(height):
if x in {0, width - 1} or y in {0, height - 1}:
flood.putpixel((x, y), BLACK)
floodfill(50, 25, RED, image)
# Save image
image.save('flood.png')
def floodfill(x, y, color, image):
# if starting color is different from desired color
# create a queue of pixels that need to be changed
# while there are pixels that need their color changed
# change the color of the pixel to what is desired
# for each pixel surrounding the curren pixel
# if the new pixel has the same color as the starting pixel
# record that its color needs to be changed
source = image.getpixel((x, y))
if source != color:
pixels = collections.deque[(x, y)]
while pixels:
x, y = place = pixels.popleft()
image.putpixel(place, color)
for x_offset in -1, 1:
x_offset += x
for y_offset in -1, 1:
y_offset += y
new_place = x_offset, y_offset
if image.getpixel(new_place) == source:
pixels.append(new_place)
if __name__ == '__main__':
main(100, 50)