如何使用Python计算地球表面多边形的面积?
标题基本上说明了一切。我需要使用 Python 计算地球表面多边形内的面积。 计算地球表面上任意多边形包围的面积说有关它的一些信息,但在技术细节上仍然含糊不清:
如果你想用更多的方式来做到这一点 “GIS”风味,那么你需要选择 您所在地区的计量单位以及 找到一个合适的投影 保留区域(并非全部保留)。自从你 正在谈论计算 任意多边形,我会使用 像兰伯特方位角的东西 等面积投影。设置 投影的原点/中心 多边形的中心,项目 多边形到新坐标 系统,然后使用计算面积 标准平面技术。
那么,我该如何在 Python 中做到这一点呢?
The title basically says it all. I need to calculate the area inside a polygon on the Earth's surface using Python. Calculating area enclosed by arbitrary polygon on Earth's surface says something about it, but remains vague on the technical details:
If you want to do this with a more
"GIS" flavor, then you need to select
an unit-of-measure for your area and
find an appropriate projection that
preserves area (not all do). Since you
are talking about calculating an
arbitrary polygon, I would use
something like a Lambert Azimuthal
Equal Area projection. Set the
origin/center of the projection to be
the center of your polygon, project
the polygon to the new coordinate
system, then calculate the area using
standard planar techniques.
So, how do I do this in Python?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
假设您有 GeoJSON 格式的科罗拉多州表示,
所有坐标都是经度、纬度。您可以使用 pyproj 来投影坐标并 Shapely 查找任何投影多边形的面积:
这是一个以感兴趣区域为中心并将其括起来的等面积投影。现在制作新的投影 GeoJSON 表示,转换为 Shapely 几何对象,并获取面积:
它非常接近测量区域。对于更复杂的特征,您需要沿着顶点之间的边缘进行采样,以获得准确的值。上述有关日期线等的所有注意事项均适用。如果您只对面积感兴趣,则可以在投影之前将要素从日期变更线平移。
Let's say you have a representation of the state of Colorado in GeoJSON format
All coordinates are longitude, latitude. You can use pyproj to project the coordinates and Shapely to find the area of any projected polygon:
That's an equal area projection centered on and bracketing the area of interest. Now make new projected GeoJSON representation, turn into a Shapely geometric object, and take the area:
It's a very close approximation to the surveyed area. For more complex features, you'll need to sample along the edges, between the vertices, to get accurate values. All caveats above about datelines, etc, apply. If you're only interested in area, you can translate your feature away from the dateline before projecting.
最简单的方法(在我看来)是将事物投影到(一个非常简单的)等面积投影中,并使用一种常用的平面技术来计算面积。
首先,如果您问这个问题,我将假设球形地球足够接近您的目的。如果没有,那么您需要使用适当的椭球体重新投影数据,在这种情况下,您将需要使用实际的投影库(现在一切都在幕后使用 proj4),例如与 GDAL/OGR 或(更友好的)pyproj。
但是,如果您同意球形地球,则无需任何专门的库即可轻松完成此操作。
要计算的最简单的等积投影是正弦投影。基本上,只需将纬度乘以纬度的长度,将经度乘以纬度的长度和纬度的余弦即可。
好吧...现在我们要做的就是计算平面上任意多边形的面积。
有多种方法可以做到这一点。我将使用 可能是这里最常见的。
无论如何,希望这能为您指明正确的方向......
The easiest way to do this (in my opinion), is to project things into (a very simple) equal-area projection and use one of the usual planar techniques for calculating area.
First off, I'm going to assume that a spherical earth is close enough for your purposes, if you're asking this question. If not, then you need to reproject your data using an appropriate ellipsoid, in which case you're going to want to use an actual projection library (everything uses proj4 behind the scenes, these days) such as the python bindings to GDAL/OGR or (the much more friendly) pyproj.
However, if you're okay with a spherical earth, it quite simple to do this without any specialized libraries.
The simplest equal-area projection to calculate is a sinusoidal projection. Basically, you just multiply the latitude by the length of one degree of latitude, and the longitude by the length of a degree of latitude and the cosine of the latitude.
Okay... Now all we have to do is to calculate the area of an arbitrary polygon in a plane.
There are a number of ways to do this. I'm going to use what is probably the most common one here.
Hopefully that will point you in the right direction, anyway...
或者简单地使用一个库: https://github.com/scisco/area
...返回区域以平方米为单位。
Or simply use a library: https://github.com/scisco/area
...returns the area in square meters.
也许有点晚了,但这里有一种不同的方法,使用吉拉德定理。它指出大圆多边形的面积是 R**2 乘以多边形之间的角度之和减去 (N-2)*pi,其中 N 是角的数量。
我认为这值得发布,因为它不依赖于 numpy 之外的任何其他库,并且它是一种与其他方法完全不同的方法。当然,这只适用于球体,所以应用到地球上时会存在一些不准确的情况。
首先,我定义一个函数来计算从点 1 沿大圆到点 2 的方位角:
现在我可以使用它来求角度,然后求面积(在下面,当然应该指定经度和纬度,并且它们应该以正确的顺序排列。另外,应该指定球体的半径。)
根据另一个回复中给出的科罗拉多坐标,以及地球半径 6371 公里,我得到的面积是 268930758560.74808
A bit late perhaps, but here is a different method, using Girard's theorem. It states that the area of a polygon of great circles is R**2 times the sum of the angles between the polygons minus (N-2)*pi where N is number of corners.
I thought this would be worth posting, since it doesn't rely on any other libraries than numpy, and it is a quite different method than the others. Of course, this only works on a sphere, so there will be some inaccuracy when applying it to the Earth.
First, I define a function to compute the bearing angle from point 1 along a great circle to point 2:
Now I can use this to find the angles, and then the area (In the following, lons and lats should of course be specified, and they should be in the right order. Also, the radius of the sphere should be specified.)
With the Colorado coordinates given in another reply, and with Earth radius 6371 km, I get that the area is 268930758560.74808
我知道十年后回答有一些优势,但对于今天看这个问题的人来说,提供更新的答案似乎是公平的。
pyproj 直接计算面积,无需调用 shapely:
结果为:269154.54988400977 km2,或报告正确值(269601.367661 km2)的-0.17%。
I know that answering 10 years later has some advantages, but to somebody that looks today at this question it seems fair to provide an updated answer.
pyproj directly calculates areas, without need of calling shapely:
The result is: 269154.54988400977 km2, or -0.17% of the reported correct value (269601.367661 km2).
您可以直接在球体上计算面积,而不是使用等积投影。
此外,根据 这个讨论,似乎吉拉德定理(sulkeh 的答案)在某些情况下并没有给出准确的结果,例如“30°月牙所包围的区域从极点到极点,以本初子午线和 30°E 为界”(请参阅此处)。
更精确的解决方案是直接在球体上执行线积分。从下面的比较可以看出,这种方法更加精确。
与所有其他答案一样,我应该提到我们假设地球是球形的警告,但我认为对于非关键目的这已经足够了。
Python 实现
这是一个使用线积分和格林定理的 Python 3 实现:
我在 sphericalgeometry 包 那里。
数值比较
科罗拉多州将作为参考,因为之前的所有答案都是在其面积上进行评估的。其精确总面积为 104,093.67 平方英里(来自美国人口普查局,第 89 页,另请参阅此处 ),或269601367661平方米。我没有找到 USCB 实际方法的来源,但我认为它是基于对地面实际测量值进行求和,或使用 WGS84/EGM2008 进行精确计算。
结论:使用直接积分更精确。
性能
我没有对不同的方法进行基准测试,将纯 Python 代码与编译的 PROJ 投影进行比较是没有意义的。直观上需要更少的计算。另一方面,三角函数可能需要大量计算。
You can compute the area directly on the sphere, instead of using an equal-area projection.
Moreover, according to this discussion, it seems that Girard's theorem (sulkeh's answer) does not give accurate results in certain cases, for example "the area enclosed by a 30º lune from pole to pole and bounded by the prime meridian and 30ºE" (see here).
A more precise solution would be to perform line integral directly on the sphere. The comparison below shows this method is more precise.
Like all other answers, I should mention the caveat that we assume a spherical earth, but I assume that for non-critical purposes this is enough.
Python implementation
Here is a Python 3 implementation which uses line integral and Green's theorem:
I wrote a somewhat more explicit version (and with many more references and TODOs...) in the sphericalgeometry package there.
Numerical Comparison
Colorado will be the reference, since all previous answers were evaluated on its area. Its precise total area is 104,093.67 square miles (from the US Census Bureau, p. 89, see also here), or 269601367661 square meters. I found no source for the actual methodology of the USCB, but I assume it is based on summing actual measurements on ground, or precise computations using WGS84/EGM2008.
Conclusion: using direct integral is more precise.
Performance
I have not benchmarked the different methods, and comparing pure Python code with compiled PROJ projections would not be meaningful. Intuitively less computations are needed. On the other hand, trigonometric functions may be computationally intensive.
这是一个使用
basemap
而不是pyproj
和shapely
进行坐标转换的解决方案。这个想法与@sgillies 所建议的相同。请注意,我添加了第五点,以便路径成为闭环。结果为 268993.609651,单位为 km^2。
更新:底图已被弃用,因此您可能需要首先考虑替代解决方案。
Here is a solution that uses
basemap
, instead ofpyproj
andshapely
, for the coordinate conversion. The idea is the same as suggested by @sgillies though. NOTE that I've added the 5th point so that the path is a closed loop.The result is 268993.609651 in km^2.
UPDATE: Basemap has been deprecated, so you may want to consider alternative solutions first.
因为地球是一个封闭的表面,所以在其表面绘制的封闭多边形会创建两个多边形区域。您还需要定义哪一个在内部,哪一个在外部!
大多数时候人们会处理小多边形,所以这是“显而易见的”,但是一旦你有海洋或大陆大小的东西,你最好确保你以正确的方式得到它。
另外,请记住,线可以通过两种不同的方式从 (-179,0) 到 (+179,0)。一个比另一个长得多。同样,大多数情况下,您会假设这是一条从 (-179,0) 到 (-180,0) 的线,即 (+180,0),然后到 (+179,0),但是天……不会的。
将经纬度视为简单的 (x,y) 坐标系,或者甚至忽略任何坐标投影都会发生扭曲和断裂的事实,可能会让您在球体上失败。
Because the earth is a closed surface a closed polygon drawn on its surface creates TWO polygonal areas. You also need to define which one is inside and which is outside!
Most times people will be dealing with small polygons, and so it's 'obvious' but once you have things the size of oceans or continents, you better make sure you get this the right way round.
Also, remember that lines can go from (-179,0) to (+179,0) in two different ways. One is very much longer than the other. Again, mostly you'll make the assumption that this is a line that goes from (-179,0) to (-180,0) which is (+180,0) and then to (+179,0), but one day... it won't.
Treating lat-long like a simple (x,y) coordinate system, or even neglecting the fact that any coordinate projection is going to have distortions and breaks, can make you fail big-time on spheres.
根据黄氏的说法,直接积分更为精确。
但是 Yellows 使用地球半径 = 6378 137m,即 WGS-84 椭球半长轴,而 Sulkeh 使用 6371 000 m。
在 Sulkeh 方法中使用半径 = 6378 137 m,得出 269533625893 平方米。
假设科罗拉多州面积的真实值(来自美国人口普查局)为 269601367661 平方米,则 Sulkeh 方法与真实值的偏差为:-0,025%,优于线积分法的 -0.07。
所以到目前为止,Sulkeh 的建议似乎更为精确。
为了能够对解进行数值比较,假设地球是球形的,所有计算都必须使用相同的地球半径。
According to Yellows' assertion, direct integral is more precise.
But Yellows use an earth radius = 6378 137m, which is the WGS-84 ellipsoid, semi-major axis, while Sulkeh use 6371 000 m.
Using a radius = 6378 137 m in the Sulkeh' method, gives 269533625893 square meters.
Assuming that the true value of Colorado area (from the US Census Bureau) is 269601367661 square meters then the variation from the ground truth of Sulkeh' method is : -0,025%, better than -0.07 with the Line integral method.
So Sulkeh' proposal seems to be the more precise so far.
In order to be able to make a numerical comparison of the solutions, with the assumption of a spherical Earth, all calculations must use the same terrestrial radius.
这是一个 Python 3 实现,其中该函数将获取纬度和经度的元组对列表,并返回投影多边形中包含的面积。它使用 pyproj 来投影坐标,然后使用 Shapely 来查找任何投影多边形的面积
对于一组纬度/经度样本,它给出的面积值接近于测量的近似值
,输出面积为 268952044107.4342 平方。山。
Here is a Python 3 implementation where the function would take a list of tuple-pairs of lats and longs and would return the area enclosed in the projected polygon.It uses pyproj to project the coordinates and then Shapely to find the area of any projected polygon
For a sample set of lats/longs, it gives an area value close to the surveyed approximation value
Which outputs an area of 268952044107.4342 Sq. Mts.