Added threshold parameter to ImageDraw.floodfill (#2599)

* added thresh option and test

* fixed up, test works and passes

* Update test_imagedraw.py

* Update test_imagedraw.py

* Update ImageDraw.py

* removed pypy skip decorator from thresh test

* Update ImageDraw.py
This commit is contained in:
nediamond 2017-07-01 05:37:02 -04:00 committed by wiredfool
parent 919150277e
commit d1b66e9dfd
2 changed files with 34 additions and 3 deletions

View File

@ -315,7 +315,7 @@ def getdraw(im=None, hints=None):
return im, handler return im, handler
def floodfill(image, xy, value, border=None): def floodfill(image, xy, value, border=None, thresh=0):
""" """
(experimental) Fills a bounded region with a given color. (experimental) Fills a bounded region with a given color.
@ -326,13 +326,17 @@ def floodfill(image, xy, value, border=None):
pixels with a color different from the border color. If not given, pixels with a color different from the border color. If not given,
the region consists of pixels having the same color as the seed the region consists of pixels having the same color as the seed
pixel. pixel.
:param thresh: Optional threshold value which specifies a maximum
tolerable difference of a pixel value from the 'background' in
order for it to be replaced. Useful for filling regions of non-
homogeneous, but similar, colors.
""" """
# based on an implementation by Eric S. Raymond # based on an implementation by Eric S. Raymond
pixel = image.load() pixel = image.load()
x, y = xy x, y = xy
try: try:
background = pixel[x, y] background = pixel[x, y]
if background == value: if _color_diff(value, background) <= thresh:
return # seed point already has fill color return # seed point already has fill color
pixel[x, y] = value pixel[x, y] = value
except (ValueError, IndexError): except (ValueError, IndexError):
@ -348,7 +352,7 @@ def floodfill(image, xy, value, border=None):
except IndexError: except IndexError:
pass pass
else: else:
if p == background: if _color_diff(p, background) <= thresh:
pixel[s, t] = value pixel[s, t] = value
newedge.append((s, t)) newedge.append((s, t))
edge = newedge edge = newedge
@ -366,3 +370,10 @@ def floodfill(image, xy, value, border=None):
pixel[s, t] = value pixel[s, t] = value
newedge.append((s, t)) newedge.append((s, t))
edge = newedge edge = newedge
def _color_diff(rgb1, rgb2):
"""
Uses 1-norm distance to calculate difference between two rgb values.
"""
return abs(rgb1[0]-rgb2[0]) + abs(rgb1[1]-rgb2[1]) + abs(rgb1[2]-rgb2[2])

View File

@ -400,6 +400,26 @@ class TestImageDraw(PillowTestCase):
self.assert_image_equal( self.assert_image_equal(
im, Image.open("Tests/images/imagedraw_floodfill2.png")) im, Image.open("Tests/images/imagedraw_floodfill2.png"))
def test_floodfill_thresh(self):
# floodfill() is experimental
# Arrange
im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im)
draw.rectangle(BBOX2, outline="darkgreen", fill="green")
centre_point = (int(W/2), int(H/2))
# Act
ImageDraw.floodfill(
im, centre_point, ImageColor.getrgb("red"),
thresh=30)
del draw
# Assert
self.assert_image_equal(
im, Image.open("Tests/images/imagedraw_floodfill2.png"))
def create_base_image_draw(self, size, def create_base_image_draw(self, size,
mode=DEFAULT_MODE, mode=DEFAULT_MODE,
background1=WHITE, background1=WHITE,