I have to count objects. At first I binarized the grid and separated the object of interest. Now I have the problem, that some objects consist of several polygon fragments. These fragments must be merged without enlarging all other polygons. As an example in the figure, the object in the middle consists three small polygons. These must be merged without changing the other polygons. I am looking for a tool to connecting polygons, that are in a defined distance to each other (for example 3 pixels)
This is just a suggestion, an approach if you will, I am sure there will be a more elegant way / more fail-safe.
- Convert rasters to polygon
- Buffer polygons with a certain search radius (depends on your data) OR convert your polygons to centroids (center points and start your search buffer from there)
- Intersect your polygons with your search buffer
- "Count" your new intersect_polygons e.g. give them unique IDs based on feature number.
- Copy the intersect_polygon ID to your original rasters
Maybe you could instead use GRASS GIS functionality? It might be worth to check out r.grow to essentially buffer your rasters and then reclass them. https://grass.osgeo.org/grass76/manuals/r.grow.html
I can't provide ready made examples, but this might help you.
This is a use case for a Binary Morphological Operation called closing.
it seems to be implemented in Qgis with OTB :
The idea of this operation is to do two steps in order to fill space between polygons.
1) first step : use a buffer of your desired distance (i.e 3 pixels in your case)
2) second step : re-use a buffer with the same distance but negative (i.e -3 pixels)
You can do it with buffer and not use the OTB implementation
this will fill open spaces and let the "lonely" polygons in the same shape. this idea comes from image processing not really GIS, but it will work.
Explanations and examples here : https://www.cs.auckland.ac.nz/courses/compsci773s1c/lectures/ImageProcessing-html/topic4.htm
You should try the integrate tool in ArcMap. Set the x and y tolerance to a value that is slightly smaller than the dimensions of a "typical" one of your objects. See documentation for that tool here: http://desktop.arcgis.com/en/arcmap/10.3/tools/data-management-toolbox/integrate.htm
After you do that, you can use the dissolve tool to merge the polygons that are touching one another.
Edit: In qgis you will want to use the v.edit function with "tool = snap" and "threshold" set to the dimensions described above. You will still need to run a dissolve after to update your counts.
How about turning the polygons into centroids and then running "Concave hull (k-nearest neighbour)" from the processing toolbox?
You could play around with the K-value and filter the resulting polygons by area (those with a large area will have "jumped" to a polygon far away), and then use the filtered, smaller polygons to select the original polygons to join.
If filtering by area turns out to be a bad approach you could play around with filtering by length/height of the bounding box of the kNN hull.
You could also try this using the vertices of the polygons instead of the centroids.
Although this approach assumes that the size of the objects are never larger than the distance between two objects, so that's a limitation.
You could create a buffered version of all the polygons with the "Fixed Buffer" tool (where you set the buffer size to 3 x cell size of you raster for example).
Then use "Join attributes by location (summary)" to intersect the buffers with the original layer. In the "Join attributes by location (summary)" dialog you choose "count" as summary to calculate to get the number of features joined.
Then you could filter out all joined buffers that have only a count of 1, since they only intersected their original, unbuffered self. Those with a higher count have probably found your multipart raster objects.
I would use python and scipy module to clusterize, following these steps:
- Rasterize your features.
- Create centroids for each polygon and store them in an array.
- Cluster them by distance
- Merge the groups of polygons.
This code should do the trick once you have the polygonized file:
from scipy.cluster.hierarchy import linkage, fcluster import geopandas as gpd features_gdf = gpd.read_file("polygonized_file.geojson") features_gdf['union'] = 0 centroids = np.array([list(list(feat.geometry.centroid.coords)) for _, feat in featured_gdf.iterrows()]) Z = linkage(centroids, 'complete') clusters = fcluster(Z, max_dist, criterion='distance') cluster_dict = defaultdict(list) for index, value in enumerate(clusters) features_gdf.iloc[index].loc['union'] = value new_feats = features_gdf.dissolve(by='union') new_feats.to_file("new_pols.geojson", driver="GeoJSON")