Transform raster donuts to circles
Let's assume I have a raster image consisting of 0's and several donut-shaped rings of 1's. This raster could for example be the result of classifying a satellite image with ponds and lakes in it into two classes: 1) pond shoreline, pixel value 1 and 2) other, pixel value 0. See image for impression.
My challenge is to fill each donut hole, creating full circles with pixel value 1. For this I have access to ArcGIS with all common functionality, as well as ENVI and Python with gdal bindings. See second image for impression of the desired outcome.I guess a majority filter will work to some extent, except when the donut holes are large.
Any suggestions on transforming donuts to circles are welcome. Bonus points for making it work with unclosed donuts as well.
What you are looking for is a Mathematical Morphology application, Closing to be precise.
If you use GDAL to read your image into a numpy array there is a number of libraries that support this operation.
scipy.ndimage is one of them and has a function for binary hole filling.
In python for a fictional binary dataset as you outlined this would transform the donuts to circles:
from osgeo import gdal from scipy.ndimage.morphology import binary_fill_holes donut_array = gdal.Open("input.tif").ReadAsArray() filled_array = binary_fill_holes(donut_array, structure=np.ones((3,3)))
This method also works with open donuts, depending on the structure you use for filling. I made a example notebook as a proof of concept and a blog post showing a more real world example.
Convert raster to polygons. Do not simplify edges.
Select donut like polygons using
How to find if polygon has a hole using field calculator in ArcGIS
Run field calculator expression on field Shape
def outer(shp): boundary=shp.boundary() part=boundary.getPart(0) pgon=arcpy.Polygon(arcpy.Array(part)) return pgon
To call it use:
outer( !Shape! )
Convert polygons to raster
If you want to fill closed donut only and don't want to test several structuring elements like for the mathematical morphology, here is an alternative :
1) Use "region group" to assign an unique value to each set of connected pixels
2) Use the raster calculator to set all but the value of your background to one.
For an ArcGIS, you can use
Block statisticsusing statistics type
Majority. May be a bit of trial and error with the neighborhood statistics is needed. For example you can try
irregularoptions with different radii to specifically keep the filling within the donuts.