为什么 gdal_grid 将图像上下颠倒?

Why does gdal_grid turn image upside-down?

我正在尝试使用 gdal_grid 从 geojson 中的表面制作高程网格。我使用这个命令:

gdal_grid -a linear:radius=0 inputSurface.geojson outputFile.tif

它似乎给出了正确的像素值,但如果我在 Global Mapper 或 QGIS 中打开结果,图像在水平轴上是 flipped/mirrored,这样 tif 就在表面正下方和上部-下。 这是什么原因,我该如何解决?

更新

我已经尝试更改地理变换,但它并没有完全解决我的问题。

我在gdalinfo中查看了生成的图像,发现左上角实际上是左下角,所以我使用SetGeoTransform来设置它。这将它移到了正确的位置,但它仍然是颠倒的。 (这可能取决于投影,稍后可能会导致问题)

我还尝试查看地理变换中的像素宽度,如下所述:

Xgeo = GT[0] + Xpixel*GT[1] + Yline*GT[2]
Ygeo = GT[3] + Xpixel*GT[4] + Yline*GT[5]

gdal_grid 返回的图像具有正 GT[5],但不幸的是将其更改为 -GT[5] 并没有任何改变。

我用来更改地理变换的代码:

transform = list(ds.GetGeoTransform())
transform = [upperLeftX, transform[1], 0, upperLeftY, 0, -transform[5]]
ds.SetGeoTransform(transform)

GDAL 的地理配准通常由两组参数指定。第一个是空间参考,它定义了坐标系(UTM、WGS,更本地化的东西)。使用 gdal.Dataset.setProjection() 设置栅格的空间参考。地理配准的第二部分是 GeoTransform,它将(行、列)像素索引转换为坐标系中的坐标。您可能需要更新地理变换以使图像 "unflipped".

GeoTransform 是一个包含 6 个值的元组,它将栅格索引与坐标相关联。

Xgeo = GT[0] + Xpixel*GT[1] + Yline*GT[2]
Ygeo = GT[3] + Xpixel*GT[4] + Yline*GT[5]

因为这些是光栅图像,所以(线、像素)或(行、列)坐标从图像的左上角开始。

[ ]----> column
 |
 |
 v row

这意味着当图像在坐标系中位于"upright"时,GT[1]将为正。类似地,有时与直觉相反,GT[5] 将是负数,因为图像中每增加一行,y 值就应该减少。这不是必需的,但很常见。

修改 GeoTransform

你说图片是颠倒的,低于应该的位置。这不能保证是一个修复,但它会让你开始。如果您面前有图像并且可以进行实验或比较坐标,那就更容易了...

import gdal
# open dataset as readable/writable
ds = gdal.Open('input.tif', gdal.GA_Update)
# get the GeoTransform as a tuple
gt = gdal.GetGeoTransform()
# change gt[5] to be it's negative, flipping the image
gt_new = (gt[0], gt[1], gt[2], gt[3], gt[4], -1 * gt[5])
# set the new GeoTransform, effectively flipping the image
ds.SetGeoTransform(gt_new)
# delete the dataset reference, flushing the cache of changes
del ds

我最终在使用 gdal_grid 时遇到了更多问题,它只是在看似随机的地方崩溃,所以我改用名为 griddata 的 scipy.interpolate 函数。这里使用了meshgrid来获取网格中的坐标,由于meshgrid的内存限制,我不得不平铺它。

import scipy.interpolate as il #for griddata
import numpy as np
# meshgrid of coords in this tile
gridX, gridY = np.meshgrid(xi[c*tcols:(c+1)*tcols], yi[r*trows:(r+1)*trows][::-1])

## Creating the DEM in this tile
zi = il.griddata((coordsT[0], coordsT[1]), coordsT[2], (gridX, gridY),method='linear',fill_value = nodata) # fill_value to prevent NaN at polygon outline
raster.GetRasterBand(1).WriteArray(zi,c*tcols,nrows-r*trows-rtrows)

线性插值似乎与 gdal_grid 应该做的一样。这实际上是通过使地理变换中的第 5 个元素为负来实现的,如问题更新中所述。

参见 scipy.interpolate.griddata 中的说明。

注意几点:

  1. 地理变换中使用的点应该在左上角
  2. y方向的分辨率应该是负的
  3. 在投影中(至少我使用的是)正 y 方向向上
  4. 在 numpy 数组中,正 y 方向向下
  5. 当使用 gdal 的 WriteArray 时,它使用左上角

希望这有助于解决其他人的困惑。

我已经通过 re-projecting gdal_grid 的结果解决了类似的问题。试一试(用您的投影替换 epsg 代码并替换 input/output 文件路径):

gdalwarp -s_srs epsg:4326 -t_srs epsg:4326 gdal_grid_result.tif inverted_output.tif

它没有。它只是渲染它的工具的标准。尝试在 QGIS 中打开它,您会发现它是正面朝上的。