I want to measure the similarity of two polygons. I want to use the average distance of the boundaries as a measure of the shape similarity.
How can I do this in PostGIS?
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It only takes a minute to sign up.Sign up to join this community
There are different ways to measure the similarity between two polygons such as average distance between the boundaries, Hausdorff distance, Turning Function, Comparing Fourier Transformation of the two polygons. Each method is suitable for one purpose.
As other users mentioned, the Hausdorff distance is a measure that shows the shape similarity. However, you should know that Hausdorff distance is the maximum distance possible between the boundaries of the two polygons. In fact if the two polygons match in 99% of their boundary but in 1% of the boundary they are 5m away from each other, the Hausdorff distance will be 5. Thus, it is a good measure to detect significant dissimilarities and it cannot tell you the average similarity between the two shapes.
Average distance on the other hand, is a average of the distances between the two boundaries and not the maximum of these distances. You can run the following code in pgAdmin to create a new function that calculates the average distance between the boundaries of two polygons.
DROP FUNCTION IF EXISTS average_distance; CREATE OR REPLACE FUNCTION average_distance (poly1 geometry, poly2 geometry, sampling_dist DOUBLE PRECISION) RETURNS DOUBLE PRECISION AS $total$ DECLARE avg_dist DOUBLE PRECISION; BEGIN WITH points AS( SELECT (ST_DumpPoints( ST_Segmentize( ST_ExteriorRing(ST_Union(poly1)) , sampling_dist ) ) ).geom ) ,poly2_corrected AS ( SELECT (ST_Union(poly2)) AS poly2_corr ) ,distances AS( SELECT ST_Distance(ST_ExteriorRing((poly2_corr)), geom) as dist FROM points, poly2_corrected ) SELECT AVG(dist) FROM distances INTO avg_dist; RETURN avg_dist; END; $total$ LANGUAGE plpgsql;
This function accepts two geometries and a sampling distance. It creates a set of points with the distance of "sampling distance" from each other on the boundary of the first geometry. Then, it measures the average distance between these points and the other geometry.
Lets say that we want to calculate the average distance between the blue and brown polygons. First, this function creates the green points. Then, it calculates the average distance between the green points (samples of the boundary of the first geometry) and the blue geometry.
The signature of the function is:
DOUBLE PRECISION average_distance (poly1 geometry, poly2 geometry, sampling_dist DOUBLE PRECISION)
And you can call it like this:
SELECT average_distance (a.geom, b.geom, 100) FROM polygons a , polygons b
Where 100m is the distance between the green points.
Be careful, your geometries should be in a metric (projected) SRID. Otherwise, the output of the function wont be correct because the sampling distance is in meters. In addition, pay attention to the fact that average_distance (geom1, geom2) is not equal to average_distance (geom2, geom1) because when you choose your green sample points on the boundary of geom1 or geom2 their distance to the other geometry wont be the same! If you want a very exact average distance then, you should choose sample points on both geometries and then calculate the distance between the corresponding points. In this case, the challenge is finding the corresponding points!!! I do not like to open that door!
I used this function to measure the shape similarity of the polygons on OpenStreetMap with the reference polygons. In this case, you should move (ST_Translate())one of the geometries so that the two geometries become concentric (to remove the impact of the displacement from average distance function). By removing the distance between the two centroids, the result of this function will indicate how similar are the two shapes.