Closed Leo-Chen00 closed 3 years ago
The paper mentions the process in section "4. SNIC-based polygonal partitioning". However I haven't implemented it yet. I will have to see, if I can reserve some time to implement it over the course of the week.
Just a few points, that may help you in the mean time:
Contour Tracing - You could use find_contours
, but you would need to run it once for every segment. I think it would be better to use a line tracing algorithm that outputs a single graph over the image (this will also be more useful for the next steps).
Simplifying Polygons - While approximate_polygon
does the right thing for a single polygon, is problematic in the way that we need shared edges between superpixels. If we simplify each polygon independently, we will likely obtain regions in the image which aren't assigned to any super-pixel.
To achieve this, the paper starts out by choosing vertices that are adjacent to three or more super-pixels (or two superpixels and the image borders), and simplifying the edges between these vertices. This ensures consistent edges between the super-pixels. The paper here explicitely mentions the Ramer–Douglas–Peucker algorithm.
I just pushed the code to the polygonize branch. Writing a efficient edge tracing took a bit longer and the code still needs clean up and proper documentation. However, the algorithm itself should work and you can already use it. Feel free to ask if something is unclear or report bugs with the new code if you find some.
I have provided a basic example at https://github.com/MoritzWillig/pysnic/blob/9d9fa28b47e24477cca0718c2f5fdbe2c4b398f5/pysnic/examples/polygons.py
Hi! Instead of only plotting,
for vertices, edges in graphs:
fig = plt.figure("SNIC with %d segments" % len(centroids))
plt.imshow(mark_boundaries(color_image, np.array(segmentation)))
for x,y in vertices.keys():
plt.scatter(x + 0.5, y + 0.5)
for edge in edges:
plt.plot([p[0] + 0.5 for p in edge], [p[1] + 0.5 for p in edge])
plt.show()
is it possible to save the results from polygonize into shapefile to be opened in GIS softwares like QGIS?
I tried but I think its not quite right..?
for vertices, edges in graphs:
polygons = convert_to_shapely_geometry(vertices, edges)
gdf = gdf.append(gpd.GeoDataFrame(geometry=polygons), ignore_index=True)
fig, ax = plt.subplots()
ax.imshow(mark_boundaries(color_image, np.array(segmentation)))
gdf.plot(ax=ax, edgecolor='red', linewidth=0.7)
gdf.to_file("poligonos_shapefile.shp")
plt.show()
Thank you very much, Leandro
Thanks for your question. Unfortunately, I'm not sure what behaviour to expect here; I guess everything should be overlaid by polygons, e.g. covered in blue? (I assume you wrote the `convert_to_shapely_geometry' yourself, as I can't find any reference to it online).
In your images I see lines connecting the start- and end-points of individual edge sequences. So, I think I missed to describe the data format more clearly: edges
does not include lines enclosing individual areas/polygons, but are only connections from one vertex - a point where 3 or more segments meet - to another.
You still need to assemble polygons by tracing along the edges. (For this, you might need to lookup additional pixel information using the unsimplified edges). You also need to take care of adding possible fully enclosed segments as holes to the enclosing polygons. Maybe you have an idea on how to implement this or, otherwise, I'll see what I can do (but this might take a while as I'm currently a bit short on time...).
Hi! Thanks for the answer!
Yes, the expected behaviour should be everything in blue. And thanks for pointing, I forgot to copy the convert_to_shapely_geometry
function :) Here it is:
import geopandas as gpd
from shapely.geometry import LineString, Polygon
def convert_to_shapely_geometry(vertices, edges):
polygons = []
for edge in edges:
edge.append(edge[0])
line = LineString([(x, y) for x, y in edge])
polygons.append(Polygon(line))
return polygons
The edge.append(edge[0])
was added because I was getting "ValueError: A LinearRing must have at least 3 coordinate tuples".
But I don't know if it was necessary since the edges, at least in orchid example, was returning edges like [(78, 80), (65, 74), (78, 80)], [(137, 48), (139, 26), (132, 15), (123, 15), (137, 48)], [(90, 48), (63, 61), (90, 48)], [(190, 399), (291, 399), (190, 399)], [(93, 389), (80, 386), (48, 347), (93, 389)], [(30, 399), (97, 399), (30, 399)]]
(last edges of the vector in orchid example).
The demo shows the way how to segment image to masks matrix but doesn't show how to convert masks to polygons ? Could you teach me how to do it in Python ?
The 'scikit-image' has
from skimage.measure import find_contours, approximate_polygon
. Should I follow this tool ?