Re: [scikit-image] fill closed contour
Oh, I see what's happening. So, in your case, both void spaces are actually holes from the perspective of the binary_fill_holes algorithm, so they both get filled. I suggest you
a) label both contours using ndi.label
b) use binary_fill_holes on each label separately
c) subtract the filled inner hole from the filled outer hole (you can optionally add back in the inner contour if you care about that single-pixel precision)
This requires being able to robustly identify the inner and outer contours, but I don't think that should be too hard? If you only have two, you can certainly find them by finding the "larger" of the two bounding boxes. You can use skimage.measure.regionprops for this.
I hope that helps!
Juan.
On 8 Jan 2018, 12:21 PM +1100, Randy Heiland
Sure - thanks.
from skimage.morphology import disk from skimage.feature import canny from scipy import ndimage as ndi import matplotlib.pyplot as plt
image = disk(100) for ix in range(200): for iy in range(200): xdel=ix-100 ydel=iy-100 if (xdel*xdel/50 + ydel*ydel/10) < 110: image[iy,ix]=0 elif (xdel*xdel/10 + ydel*ydel/50) < 110: image[iy,ix]=0
edges = canny(image*255.) # canny expect grayscale, i.e. 0-255 ??!
fill = ndi.binary_fill_holes(edges) # I don't understand the params; can I seed a region to fill?
fig, axes = plt.subplots(ncols=3, figsize=(9, 3)) ax = axes.ravel()
ax[0].imshow(image, cmap=plt.cm.gray, interpolation='nearest') #ax[0].imshow(invert_img, cmap=plt.cm.gray) #ax[0].set_title('Inverted image') ax[0].set_title('Original image')
ax[1].imshow(edges*1, cmap=plt.cm.gray, interpolation='nearest') ax[1].set_title('Canny edges')
ax[2].imshow(fill, cmap=plt.cm.spectral, interpolation='nearest') ax[2].set_title('Fill')
plt.show()
On Sun, Jan 7, 2018 at 6:57 PM, Juan Nunez-Iglesias
wrote: Hi Randy, I was going to suggest binary fill holes. Do you mind posting your image and the code you’ve tried so we can troubleshoot?
Thanks,
Juan.
On 8 Jan 2018, 9:48 AM +1100, Randy Heiland
, wrote: If I have a binary image with, say, just a contour boundary (simple example: a white background with a black circle, i.e. an "o"), how can I fill the inside of the contour? I've played with both the watershed segmentation and the scipy.ndimage.binary_fill_holes, without success.
thanks, Randy _______________________________________________ scikit-image mailing list scikit-image@python.org https://mail.python.org/mailman/listinfo/scikit-image
_______________________________________________ scikit-image mailing list scikit-image@python.org https://mail.python.org/mailman/listinfo/scikit-image
_______________________________________________ scikit-image mailing list scikit-image@python.org https://mail.python.org/mailman/listinfo/scikit-image
Thanks Juan. I understand better what the ndi.measurements.label can do
for me now. I've tweaked my previous script and attached the resulting
output. Does it make sense that I need to "thicken" the contours in order
to get the desired features/regions, or is there something I'm still
missing?
------------
from skimage.morphology import disk
from skimage.feature import canny
from skimage.filters import rank
from scipy import ndimage as ndi
import matplotlib.pyplot as plt
import numpy as np
image = disk(100)
for ix in range(200):
for iy in range(200):
xdel=ix-100
ydel=iy-100
if (xdel*xdel/50 + ydel*ydel/10) < 110:
image[iy,ix]=0
elif (xdel*xdel/10 + ydel*ydel/50) < 110:
image[iy,ix]=0
edges = canny(image*255.) # canny expect grayscale, i.e. 0-255 ??!
thicken = rank.gradient(edges, disk(1)) < 5
bdy = thicken.astype(np.uint8)*255
labeled_array, num_features = ndi.measurements.label(edges*1)
print("num_features (edges*1)=",num_features)
labeled_array2, num_features2 = ndi.measurements.label(bdy)
print("num_features (thick)=",num_features2)
fill = ndi.binary_fill_holes(edges)
fig, axes = plt.subplots(ncols=2, nrows=2, figsize=(6, 7))
ax = axes.ravel()
ax[0].imshow(edges*1, cmap=plt.cm.gray, interpolation='nearest')
ax[0].set_title('Canny edges')
ax[1].imshow(labeled_array, cmap=plt.cm.spectral, interpolation='nearest')
ax[1].set_title('labeled_array')
ax[2].imshow(bdy, cmap=plt.cm.gray, interpolation='nearest')
ax[2].set_title('bdy')
ax[3].imshow(labeled_array2, cmap=plt.cm.spectral, interpolation='nearest')
ax[3].set_title('labeled_array2')
plt.axis('off')
plt.show()
-->
num_features (edges*1)= 216
num_features (thick)= 6
-Randy
On Sun, Jan 7, 2018 at 11:36 PM, Juan Nunez-Iglesias
Oh, I see what's happening. So, in your case, both void spaces are actually holes from the perspective of the binary_fill_holes algorithm, so they both get filled. I suggest you
a) label both contours using ndi.label b) use binary_fill_holes on each label separately c) subtract the filled inner hole from the filled outer hole (you can optionally add back in the inner contour if you care about that single-pixel precision)
This requires being able to robustly identify the inner and outer contours, but I don't think that should be too hard? If you only have two, you can certainly find them by finding the "larger" of the two bounding boxes. You can use skimage.measure.regionprops for this.
I hope that helps!
Juan.
On 8 Jan 2018, 12:21 PM +1100, Randy Heiland
, wrote: Sure - thanks.
from skimage.morphology import disk from skimage.feature import canny from scipy import ndimage as ndi import matplotlib.pyplot as plt
image = disk(100) for ix in range(200): for iy in range(200): xdel=ix-100 ydel=iy-100 if (xdel*xdel/50 + ydel*ydel/10) < 110: image[iy,ix]=0 elif (xdel*xdel/10 + ydel*ydel/50) < 110: image[iy,ix]=0
edges = canny(image*255.) # canny expect grayscale, i.e. 0-255 ??!
fill = ndi.binary_fill_holes(edges) # I don't understand the params; can I seed a region to fill?
fig, axes = plt.subplots(ncols=3, figsize=(9, 3)) ax = axes.ravel()
ax[0].imshow(image, cmap=plt.cm.gray, interpolation='nearest') #ax[0].imshow(invert_img, cmap=plt.cm.gray) #ax[0].set_title('Inverted image') ax[0].set_title('Original image')
ax[1].imshow(edges*1, cmap=plt.cm.gray, interpolation='nearest') ax[1].set_title('Canny edges')
ax[2].imshow(fill, cmap=plt.cm.spectral, interpolation='nearest') ax[2].set_title('Fill')
plt.show()
On Sun, Jan 7, 2018 at 6:57 PM, Juan Nunez-Iglesias
wrote: Hi Randy, I was going to suggest binary fill holes. Do you mind posting your image and the code you’ve tried so we can troubleshoot?
Thanks,
Juan.
On 8 Jan 2018, 9:48 AM +1100, Randy Heiland
, wrote: If I have a binary image with, say, just a contour boundary (simple example: a white background with a black circle, i.e. an "o"), how can I fill the inside of the contour? I've played with both the watershed segmentation and the scipy.ndimage.binary_fill_holes, without success.
thanks, Randy _______________________________________________ scikit-image mailing list scikit-image@python.org https://mail.python.org/mailman/listinfo/scikit-image
_______________________________________________ scikit-image mailing list scikit-image@python.org https://mail.python.org/mailman/listinfo/scikit-image
_______________________________________________ scikit-image mailing list scikit-image@python.org https://mail.python.org/mailman/listinfo/scikit-image
_______________________________________________ scikit-image mailing list scikit-image@python.org https://mail.python.org/mailman/listinfo/scikit-image
participants (2)
-
Juan Nunez-Iglesias
-
Randy Heiland