6

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)

enter image description here

3
  • 1
    Welcome to GSE ! Please specify if you are looking for a script method or a manual method. Commented May 29, 2019 at 10:06
  • I'm not a Qgis expert and I'm not sure about the difference. I would like to install the step in the model builder. I probably need a manual method.
    – Hardau
    Commented May 29, 2019 at 10:54
  • I would suggest to use a "majority filter" first on your grid, which will result in more homogenous regions.
    – eurojam
    Commented May 29, 2019 at 14:31

6 Answers 6

3

This is just a suggestion, an approach if you will, I am sure there will be a more elegant way / more fail-safe.

  1. Convert rasters to polygon
  2. 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)
  3. Intersect your polygons with your search buffer
  4. "Count" your new intersect_polygons e.g. give them unique IDs based on feature number.
  5. 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.

1

This is a use case for a Binary Morphological Operation called closing.

it seems to be implemented in Qgis with OTB :

https://docs.qgis.org/2.8/en/docs/user_manual/processing_algs/otb/feature_extraction.html

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

2
  • This tool seems to be part of the Orfeo toolbox which isn't a default in QGIS anymore. Which is a pity, because it seems like the best solution (to me at least).
    – hexamon
    Commented Oct 1, 2019 at 8:30
  • 1
    yes, the tool I linked is part of OTB tools, so not by default in QGIS. But you can still do two buffers and reach the same result. Commented Oct 1, 2019 at 8:56
0

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.

https://grass.osgeo.org/grass77/manuals/v.edit.html

0

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.

0

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.

0

I would use python and scipy module to clusterize, following these steps:

  1. Rasterize your features.
  2. Create centroids for each polygon and store them in an array.
  3. Cluster them by distance
  4. 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)[0]) 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")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.