Merge pull request #3294 from yo1995/perfperf-improv-ImageDraw-floodfill

Performance improvement of ImageDraw.floodfill()
This commit is contained in:
Andrew Murray 2018-09-16 12:46:50 +10:00 committed by GitHub
commit 7b4040f991
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -341,6 +341,7 @@ def floodfill(image, xy, value, border=None, thresh=0):
homogeneous, but similar, colors. homogeneous, but similar, colors.
""" """
# based on an implementation by Eric S. Raymond # based on an implementation by Eric S. Raymond
# amended by yo1995 @20180806
pixel = image.load() pixel = image.load()
x, y = xy x, y = xy
try: try:
@ -350,24 +351,29 @@ def floodfill(image, xy, value, border=None, thresh=0):
pixel[x, y] = value pixel[x, y] = value
except (ValueError, IndexError): except (ValueError, IndexError):
return # seed point outside image return # seed point outside image
edge = [(x, y)] edge = {(x, y)}
full_edge = set() # use a set to keep record of current and previous edge pixels to reduce memory consumption
while edge: while edge:
newedge = [] new_edge = set()
for (x, y) in edge: for (x, y) in edge: # 4 adjacent method
for (s, t) in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)): for (s, t) in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
if (s, t) in full_edge:
continue # if already processed, skip
try: try:
p = pixel[s, t] p = pixel[s, t]
except (ValueError, IndexError): except (ValueError, IndexError):
pass pass
else: else:
full_edge.add((s, t))
if border is None: if border is None:
fill = _color_diff(p, background) <= thresh fill = _color_diff(p, background) <= thresh
else: else:
fill = p != value and p != border fill = p != value and p != border
if fill: if fill:
pixel[s, t] = value pixel[s, t] = value
newedge.append((s, t)) new_edge.add((s, t))
edge = newedge full_edge = edge # discard pixels processed
edge = new_edge
def _color_diff(rgb1, rgb2): def _color_diff(rgb1, rgb2):