geotiff 坐标转换

    科技2022-07-12  130

    geotiff 坐标转换

    If you’re building a geospatial application in Node.js or clientside JavaScript, you may need to eventually extract data from a raster at a specific coordinate — or a large number of them. This historically hasn’t been very straightforward in JavaScript, as the most common format for geospatial rasters is the GeoTIFF file type, which cannot be easily parsed.

    如果要在Node.js或客户端JavaScript中构建地理空间应用程序,则最终可能需要从栅格中的特定坐标(或大量坐标)提取数据。 从历史上看,这在JavaScript中并不是很简单,因为地理空间栅格的最常见格式是GeoTIFF文件类型,该类型不易解析。

    There are a few solutions available, and with recent advances in the JavaScript language and Node ecosystem, this is no longer the technological hurdle it used to be.

    有一些解决方案可用,并且随着JavaScript语言和Node生态系统的最新发展,这不再是过去的技术障碍。

    GDAL? (GDAL?)

    Before JavaScript had any real ability to parse GeoTIFF files — unless you rolled your own wrappers around a lower-level programming language — your best bet was to call another application via exec(), such as a python script or command-line utility. One that immediately comes to mind is gdallocationinfo , which is part of the GDAL suite and can be used to query a raster using a latitude and longitude, like so:

    在JavaScript真正具有解析GeoTIFF文件的能力之前(除非您使用较低级的编程语言来包装自己的包装程序exec() ,最好的选择是通过exec()调用另一个应用程序,例如python脚本或命令行实用程序。 马上想到的是gdallocationinfo ,它是GDAL套件的一部分,可用于使用纬度和经度查询栅格,如下所示:

    gdallocationinfo -valonly -wgs84 <geotiff filename> <longitude> <latitude>

    If you’re just querying a point in a raster, this approach is good enough. However, there are some issues:

    如果您只是在栅格中查询一个点,那么这种方法就足够了。 但是,存在一些问题:

    If doing this clientside, the user must have GDAL installed.

    如果在此客户端进行操作,则用户必须已安装GDAL。

    There is an overhead to calling this via exec() in addition to parsing the file every time.

    除了每次都解析文件外,通过exec()调用它也会产生开销。

    As a real-world example, using this approach to query a point across 60 GeoTIFF files with hundreds of bands apiece required about ten seconds of processing time on a reasonably fast computer. Multiple points would quickly add up to an unreasonable amount of time.

    作为一个实际示例,使用这种方法来查询60个带有数百个带的GeoTIFF文件中的一个点,在相当快的计算机上需要大约十秒钟的处理时间。 多个点将很快增加不合理的时间。

    If calling the shell script and loading the file is most of the overhead, then why not use the gdal npm package which provides bindings for the library? As of September 2020, this was also not a very good option, mostly because it requires GDAL version 2 (current version is 3.1), so if you have GDAL installed on your machine or server you are going to have to do some difficult version juggling to make it work, if you can even make it build from source in the first place. It also does not provide asynchronous bindings, meaning you have to set up web workers if you don’t want your thread to be blocked (this is problematic if running a Node.js server, depending on how much processing you intend to do).

    如果调用shell脚本并加载文件是大部分开销,那么为什么不使用提供库绑定的gdal npm软件包呢? 截至2020年9月,这也不是一个很好的选择,主要是因为它需要GDAL版本2(当前版本为3.1),因此,如果您在计算机或服务器上安装了GDAL,则必须进行一些困难的版本调整使它工作,即使您甚至可以首先从源代码构建它。 它还不提供异步绑定,这意味着如果您不希望阻塞线程,则必须设置Web Worker(如果运行Node.js服务器,这取决于要执行的处理量,这是有问题的)。

    Image by author 图片作者

    GeoTIFF.js (GeoTIFF.js)

    This library has been around for 4–5 years and reached version 1.0.0 just a few months ago. Not only does GeoTIFF.js provide reading and writing functionality for the eponymous file type, it does so with built-in asynchronous capabilities and even a web worker pool for more serious processing tasks.

    这个库已经存在了4-5年,而几个月前达到了1.0.0版本。 GeoTIFF.js不仅提供同名文件类型的读写功能,而且还具有内置的异步功能,甚至还提供用于处理更严格的处理任务的Web工作程序池。

    One thing the library does not do natively is provide a simple means for querying a geographic coordinate in a raster, so you will need to write this functionality yourself. However, it is quite easy once you extract the geographic metadata from the GeoTIFF.

    库本身没有做的一件事就是提供一种简单的方法来查询栅格中的地理坐标,因此您需要自己编写此功能。 但是,一旦从GeoTIFF中提取了地理元数据,这将非常容易。

    First, load the GeoTIFF and its associated image. For best results, make sure it has been projected to WGS84 first. If you keep the file in memory, you will not deal with the overhead of reading it repeatedly from disk, as small as it may be:

    首先,加载GeoTIFF及其关联的图像。 为了获得最佳结果,请确保首先将其投影到WGS84。 如果将文件保留在内存中,则不会处理从磁盘重复读取文件的开销,因为它可能很小:

    const file = await geoTIFF.fromFile(<geotiff filename>);const image = await file.getImage();

    Now, grab the geographic information and calculate a few numbers that you’ll use to figure out which pixel corresponds to a given latitude and longitude:

    现在,获取地理信息并计算一些数字,以找出哪个像素对应给定的经度和纬度:

    const bbox = image.getBoundingBox();const pixelWidth = image.getWidth();const pixelHeight = image.getHeight();const bboxWidth = bbox[ 2 ] - bbox[ 0 ];const bboxHeight = bbox[ 3 ] - bbox[ 1 ];

    Bounding box data is stored as [xMin, yMin, xMax, yMax]. We can now take the coordinate and figure out which pixel it corresponds to:

    边界框数据存储为[xMin, yMin, xMax, yMax] 。 现在我们可以获取坐标并找出对应的像素:

    const widthPct = ( <longitude> - bbox[ 0 ] ) / bboxWidth;const heightPct = ( <latitude> - bbox[ 1 ] ) / bboxHeight;const xPx = Math.floor( pixelWidth * widthPct );const yPx = Math.floor( pixelHeight * ( 1 - heightPct ) );

    Now what? You can of course, extract the entire raster from the image. For smaller images, this is great, and you can keep the entire array of data in memory, which is very cheap and quick to query. However, if you are working with a large raster and/or a lot of bands, this is going to take a very long time and quite a bit of memory.

    怎么办? 当然,您可以从image提取整个栅格。 对于较小的图像,这很好,您可以将整个数据数组保留在内存中,这非常便宜且可以快速查询。 但是,如果您使用较大的栅格和/或很多波段,这将需要很长时间和大量内存。

    Luckily, GeoTIFF.js provides a method to extract a raster using a bounding box — so we’ll just use a bounding box that is one pixel by one pixel. This turns out to be pleasantly quick, even on very large rasters with lots of bands (also, GeoTIFF.js has support for tiled rasters — tiling large rasters should improve performance further, but I haven’t tested it.):

    幸运的是,GeoTIFF.js提供了一种使用边界框提取栅格的方法-因此,我们仅使用一个像素乘一个像素的边界框。 事实证明,这是令人愉悦的快速,即使在具有很多波段的非常大的栅格上(GeoTIFF.js也支持平铺栅格-平铺大栅格应进一步提高性能,但我尚未对其进行测试。):

    const window = [ xPx, yPx, xPx + 1, yPx + 1 ];const data = await image.readRasters( {window} );

    You now have an array of all the bands at this specific point.

    现在,您在此特定点具有所有波段的数组。

    [ Float32Array [ 0.07990912348031998 ], Float32Array [ 0.16144123673439026 ], Float32Array [ 0.1751343011856079 ], Float32Array [ 0.2101452350616455 ], Float32Array [ 0.2505287826061249 ], Float32Array [ 0.3461601734161377 ] ...]

    Note that you can have readRasters use a pool of web workers, which adds multi-threading potential, but with such tiny bounding boxes, the overhead of spinning up a new web worker drastically decreases performance, so it’s not recommended for this approach.

    请注意,您可以让readRasters使用Web Worker池,这增加了多线程的潜力,但是由于边界框很小,因此readRasters新的Web Worker的开销会大大降低性能,因此不建议使用此方法。

    Image by author 图片作者

    性能比较 (Performance Comparison)

    How does the GeoTIFF.js query logic stack up against a call to gdallocationinfo? This can depend a bit on how many files you are opening (especially repeatedly), but my results, both experimentally and in practice, have been decisive. On a solid state drive, I queried the same raster (about 500px by 200px, with 250 bands) using the same latitude and longitude and recorded the elapsed milliseconds.

    如何将GeoTIFF.js查询逻辑与对gdallocationinfo的调用进行gdallocationinfo ? 这可能取决于您打开的文件数量(尤其是重复打开的文件数量),但是我的实验和实践结果都是决定性的。 在固态驱动器上,我使用相同的纬度和经度查询了相同的栅格(大约500px x 200px,具有250条带),并记录了经过的毫秒数。

    exec(gdallocationinfo…)

    exec(gdallocationinfo ...)

    Run 1: 62msRun 2: 163msRun 3: 64msRun 4: 68msRun 5: 176ms----Average: 106.6ms

    This method seems to experience random hiccups every few runs that are detrimental to its overall processing time. This has been noted across my development computer in addition to my servers.

    这种方法似乎每运行几次就会出现随机打ic,这不利于其整体处理时间。 除服务器外,这在我的开发计算机上也已注意到。

    GeoTIFF.js

    GeoTIFF.js

    Run 1: 58msRun 2: 60msRun 3: 60msRun 4: 54msRun 5: 57ms----Average: 57.8ms

    Not only was this library slightly quicker than a call to gdallocationinfo, performance was very consistent, nearly halving the average processing time.

    该库不仅比调用gdallocationinfo快一点,而且性能非常稳定,几乎使平均处理时间减少了一半。

    Using this technique, I was able to improve the performance of a JavaScript weather forecasting algorithm nearly threefold, as it reads from about 60 GeoTIFFs and thousands of bands. With gdallocationinfo, this typically took around ten seconds. After switching to the above technique using GeoTIFF.js, the algorithm runs in just under three seconds.

    使用这项技术,我可以将JavaScript天气预报算法的性能提高近三倍,因为它可以读取约60个GeoTIFF和数千个波段。 使用gdallocationinfo ,通常大约需要十秒钟。 使用GeoTIFF.js切换到上述技术后,该算法将在不到三秒钟的时间内运行。

    Of course, there are other external libraries that read GeoTIFF data, but it doesn’t seem likely that invoking them with exec() will provide much of an edge over GeoTIFF.js, especially since you will be unable to keep the GeoTIFF images or the data itself (as a raw numeric array) cached within your JavaScript application.

    当然,还有其他一些外部库可以读取GeoTIFF数据,但是使用exec()调用它们似乎不太可能在GeoTIFF.js上提供很多优势,尤其是因为您将无法保留GeoTIFF图像或在JavaScript应用程序中缓存的数据本身(作为原始数字数组)。

    Yes, you could always read from GeoTIFFs in a language or framework actually suited for working with this data, but this paradigm is beginning to change. JavaScript continues to grow and mature, servers built in Node.js are becoming more common, and implementing something like a browser-based weather model analysis application is no longer a pipe dream. You may need to use this technique. Maybe you’ll come up with something even quicker, and if so, I’d love to hear it!

    是的,您始终可以使用实际上适合于处理此数据的语言或框架从GeoTIFF中读取内容,但是这种范例正在开始改变。 JavaScript继续发展和成熟,内置在Node.js中的服务器变得越来越普遍,实现基于浏览器的天气模型分析应用程序之类的事情不再是梦pipe以求的事情。 您可能需要使用此技术。 也许您会想出更快的方法,如果是这样,我很想听听!

    翻译自: https://towardsdatascience.com/geotiff-coordinate-querying-with-javascript-5e6caaaf88cf

    geotiff 坐标转换

    相关资源:GeotiffParser(tiff格式数据解析器)
    Processed: 0.010, SQL: 8