0

Looking for a way to fill all of the values within an arbitrary shape with a gradient of values... which must follow the outline of the shape. For example, the "shaped gradient" fill tool in gimp would give you:

enter image description here

Output should be a 2d numpy array.

1 Answers1

2

You could take a look at scipy.ndimage.morphology.distance_transform_edt. This will return the distance to the closest background pixel.

First, you will need to create a binary image of your arbitrary shape

import numpy as np
from scipy.ndimage.morphology import distance_transform_edt

# create dummy image
a = np.arange(100).reshape([10, 10])

# use threshold to define arbitrary shape
b = (a > 54).astype('uint8')
print(b)

[[0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]]

Then, apply the distance transform to the binary image. The output will look like below, with smaller values corresponding to those closer to the edge of the binary object.

# apply Euclidean distance transform
d = distance_transform_edt(b)
print(d.round(2))

[[0.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   0.   0.   1.   1.   1.   1.   1.  ]
 [1.   1.   1.   1.   1.   1.41 2.   2.   2.   2.  ]
 [2.   2.   2.   2.   2.   2.24 2.83 3.   3.   3.  ]
 [3.   3.   3.   3.   3.   3.16 3.61 4.   4.   4.  ]
 [4.   4.   4.   4.   4.   4.12 4.47 5.   5.   5.  ]]

A color map could then be defined for the range of values in d.

  • Thanks! That gets me 90% of the way there. Then all I have to do is normalize it and use numpy.linspace() to pick my color from a gradient. Perfect! – TheHeadlessSourceMan Jun 06 '20 at 14:24