Question

I'm working with shapely to do GIS, but I'm running into memory errors when loading the geometry of each zip code into memory because the geometry is so jagged and complicated.

I'd like to make the shape smaller in memory by reducing the number of boundary points as low as possible without distorting the shape too much. Using the convex hull seems like one potential answer, as could simply throwing away lots of points from the boundary. I'm wondering if there's something already out there that solves this problem.

Was it helpful?

Solution

Try using the geometry's simplify method, specifying a tolerance distance.

OTHER TIPS

Came across this old post, as I had a similar problem. My solution was as follows:

Generate polygons from an area mask.

Here it's two areas.

import shapely.geometry
import cv2
import numpy as np

# gen. mask
mask=np.zeros((600,600),dtype=bool)
mask[300:500,300:500]=True
mask[:150,30:120]=True
mask[70:120,30:220]=True
mask[100:200,200:260]=True

# get contours == polygon
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours = [i.reshape((-1, 2)) for i in contours]

Simplified the polygon(s)

simplify_tolerance = .1

# simplify contours with shapely
contours_s = []
for i in contours:
    poly = shapely.geometry.Polygon(i.reshape((-1, 2)))
    poly_s = poly.simplify(tolerance=simplify_tolerance)

    # store the boundary coordinates as a numpy array
    contours_s.append(np.array(poly_s.boundary.coords[:]))

Plot

plt.figure(figsize=(4,4))
plt.imshow(mask, label='2D mask')

for i, c_i in enumerate(contours_s):
    plt.plot(*c_i.reshape((-1, 2)).T, '-', label=f'cv2 contours {i}')
    
for i, c_i in enumerate(contours_s):
    plt.plot(*c_i.T, 'o', label=f'shapely simplify {i}')
    
plt.legend()
plt.tight_layout()

Plot

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top