如何从Perl中的USGS NED DEM GridFloat文件中读取高程

时间:2014-08-21 22:15:38

标签: perl elevation

我从USGS NED(1")下载了大量的GridFloat(.flt,.hdr)DEM文件,以便在我的网站上实现我自己的提升服务。我希望能够从纬度和经度作为输入查找此文件集的高程。我使用Perl进行网站开发。这些文件有一个传统的命名方案,我可以使用lat / lng获得相应的tile文件名。然而,访问文件的内部是我遇到问题的地方。

我知道文件格式相当简单(.flt,显然叫做#34; Gridfloat"),但是我可以用一些帮助来计算用于计算文件中我需要寻找的位置的幻数对于给定的lat / lng,以及如何处理字节顺序等等,以便最终得到一个高程。从我的理解,显然行排序可能是一个问题,以及字节顺序。我正在寻找一种不涉及使用任何第三方库(如GDAL)的配方,我认为这些库过于复杂且对我想做的事情来说很慢。我认为应该可以打开文件,根据某些计算寻找位置,读取一些字节,然后将它们解压缩到正确的字节顺序。这是一个示例.hdr文件,随附floatn48w097_1.flt,我认为它有必要的信息。 .zip附带了许多其他文件,包括.prj,但我相信这些文件适用于像ArcInfo这样的商业程序。我认为我需要的所有内容应该位于以下.hdr文件中。

ncols         3612
nrows         3612
xllcorner     -97.00166666667
yllcorner     46.99833333333
cellsize      0.000277777777778
NODATA_value  -9999
byteorder     LSBFIRST

我真正希望的是从lat / lng计算行和列的公式,然后是将行/列转换为搜索位置的另一个公式,要读取的字节数以及如何将这些原始字节转换为整数(或者这些文件包含的任何内容)。我觉得这可能是一个非常快速的操作,没有涉及大型库的所有开销,这些库似乎专注于做很多我不需要的东西。

我不需要Perl代码,只显示行/ col偏移计算的伪代码就足够了。我相信文件是二进制格式,一个4字节数字的简单网格。与上面的.hdr文件一起使用的文件示例的大小为52186176,当你将ncols乘以nrows(来自.hdr)时,你会得到13046544.它很好地将文件大小除以4.所以我假设它& #39;只需基于lat / lng获得行/ col的正确公式,然后将字节调整到正确的顺序。我没有做那么多。

我在这里找到了一些Gridfloat格式的引用:coolutils.com/formats/flt所以显然该文件由64位浮点值网格组成。

谢谢!

2 个答案:

答案 0 :(得分:1)

好的,我想我有答案。以下是Perl例程,当使用USGS NED1 .flt文件进行测试时,它似乎会返回合理的高程值。该脚本将纬度和经度作为命令行参数,查找文件并索引到网格中。

#!/usr/bin/perl

use strict;
use POSIX;
use Math::Round;

sub get_elevation
{
    my ($lat, $lng) = @_;

    my $lat_degree = ceil ($lat);
    my $lng_degree = floor ($lng);

    my $lat_letter = ($lat >= 0) ? 'n' : 's';
    my $lng_letter = ($lng >= 0) ? 'e' : 'w';

    my $lng_tilenum = abs($lng_degree);
    my $lat_tilenum = abs($lat_degree);

    my $tilename =  $lat_letter . sprintf('%02d', $lat_tilenum) . $lng_letter . sprintf('%03d',$lng_tilenum);
    my $path = "/data/elevation/ned1/$tilename/float${tilename}_1.flt";

    print "path = $path\n";

    die "No such file" if (!-e($path));

    my ($lat_fraction, $lat_integral) = modf (abs($lat));
    my $row = floor ((1 - $lat_fraction) * 3600);

    my ($lng_fraction, $lng_integral) = modf (abs($lng));
    my $col = floor ((1 - $lng_fraction) * 3600);

    open(FILE, "<$path");

    my $pos = (3612 * 4 * 6) + (3612 * 4 * $row) + (4 * 6) + ($col * 4);

    seek (FILE, $pos, SEEK_SET);

    my $buffer;
    read (FILE, $buffer, 4);

    close (FILE);

    my ($elevation) = unpack('f', $buffer);

    if ($elevation == -9999)
    {
        return 'undefined';
    }

    return $elevation;
}

my $lat = $ARGV[0];
my $lng = $ARGV[1];
my $elevation = get_elevation ($lat, $lng);

print "Elevation for ($lat, $lng) = $elevation meters (", $elevation * 3.28084, " feet)\n";

希望这可能对其他试图做同样事情的人有用......我现在已经测试了这种方法,它似乎产生了比3&#34更平滑的高清外观。 ; SRTM数据。

答案 1 :(得分:0)

尼尔让我走上了正确的轨道,但我认为他的原始答案存在一些问题。我已经添加了一些修复和改进,包括从1/3弧秒(10米)数据集中即时下载所需的磁贴,正确解析头文件,以及我认为纠正索引。 / p>

这仍然主要是说明性的,应该在生产使用之前进行改进,特别是挂在头信息和重复查询的文件句柄上。

https://gist.github.com/biomiker/32fe34e1fa1bb49ae1135ab6652f596d