如何使用Python使用地面控制点对未参考航空影像进行地理参考

7
我有一系列未参考的航空影像,希望使用Python进行地理参考。这些图像在空间上是相同的(实际上它们是从视频中提取的帧),我通过手动在ArcMap中对其中一个帧进行地理参考来获取了它们的地面控制点。我想将我获得的地面控制点应用于所有后续图像,并因此获得一个geo-tiff或每个处理图像的相应世界文件(.jgw)的JPEG文件。我知道可以使用arcpy来完成这项工作,但我没有访问arcpy,并且如果可能的话,我真的很想使用免费开源模块。
我的坐标系统是NZGD2000(epsg 2193),以下是我希望应用于我的图像的控制点表:
176.412984,-310.977264,1681255.524654,6120217.357425
160.386905,-141.487145,1681158.424227,6120406.821253
433.204947,-310.547238,1681556.948690,6120335.658359
这是一个示例图像:https://imgur.com/a/9ThHtOz 我已经阅读了大量关于GDAL和rasterio的信息,但我没有任何使用它们的经验,并且无法将我找到的代码片段适应于我的特定情况。
尝试使用Rasterio:
import cv2
from rasterio.warp import reproject
from rasterio.control import GroundControlPoint
from fiona.crs import from_epsg

img = cv2.imread("Example_image.jpg")

# Creating ground control points (not sure if I got the order of variables right):
points = [(GroundControlPoint(176.412984, -310.977264, 1681255.524654, 6120217.357425)),
          (GroundControlPoint(160.386905, -141.487145, 1681158.424227, 6120406.821253)),
          (GroundControlPoint(433.204947, -310.547238, 1681556.948690, 6120335.658359))]

# The function requires a parameter "destination", but I'm not sure what to put there.
#   I'm guessing this may not be the right function to use
reproject(img, destination, src_transform=None, gcps=points, src_crs=from_epsg(2193),
                        src_nodata=None, dst_transform=None, dst_crs=from_epsg(2193), dst_nodata=None,
                        src_alpha=0, dst_alpha=0, init_dest_nodata=True, warp_mem_limit=0)

GDAL尝试:

from osgeo import gdal 
import osr

inputImage = "Example_image.jpg"
outputImage = "image_gdal.jpg"

dataset = gdal.Open(inputImage) 
I = dataset.ReadAsArray(0,0,dataset.RasterXSize,dataset.RasterYSize)

outdataset = gdal.GetDriverByName('GTiff') 
output_SRS = osr.SpatialReference() 
output_SRS.ImportFromEPSG(2193) 
outdataset = outdataset.Create(outputImage,dataset.RasterXSize,dataset.RasterYSize,I.shape[0]) 
for nb_band in range(I.shape[0]):
    outdataset.GetRasterBand(nb_band+1).WriteArray(I[nb_band,:,:])

# Creating ground control points (not sure if I got the order of variables right):
gcp_list = [] 
gcp_list.append(gdal.GCP(176.412984, -310.977264, 1681255.524654, 6120217.357425))
gcp_list.append(gdal.GCP(160.386905, -141.487145, 1681158.424227, 6120406.821253))
gcp_list.append(gdal.GCP(433.204947, -310.547238, 1681556.948690, 6120335.658359))

outdataset.SetProjection(srs.ExportToWkt()) 
wkt = outdataset.GetProjection() 
outdataset.SetGCPs(gcp_list,wkt)

outdataset = None

我不是很清楚如何使上面的代码工作,非常感谢您对此提供任何帮助。

3个回答

15

我最终阅读了一本名为“使用Python进行地理处理”的书籍,最终找到了适合我的解决方案。以下是我根据自己的问题修改后的代码:

import shutil
from osgeo import gdal, osr

orig_fn = 'image.tif'
output_fn = 'output.tif'

# Create a copy of the original file and save it as the output filename:
shutil.copy(orig_fn, output_fn)
# Open the output file for writing for writing:
ds = gdal.Open(output_fn, gdal.GA_Update)
# Set spatial reference:
sr = osr.SpatialReference()
sr.ImportFromEPSG(2193) #2193 refers to the NZTM2000, but can use any desired projection

# Enter the GCPs
#   Format: [map x-coordinate(longitude)], [map y-coordinate (latitude)], [elevation],
#   [image column index(x)], [image row index (y)]
gcps = [gdal.GCP(1681255.524654, 6120217.357425, 0, 176.412984, 310.977264),
gdal.GCP(1681158.424227, 6120406.821253, 0, 160.386905, 141.487145),
gdal.GCP(1681556.948690, 6120335.658359, 0, 433.204947, 310.547238)]

# Apply the GCPs to the open output file:
ds.SetGCPs(gcps, sr.ExportToWkt())

# Close the output file in order to be able to work with it in other programs:
ds = None

1
谢谢您的回答!我有一个类似的问题,这帮助我理解了如何处理它。我知道你可能不会回答这个问题,但是你有没有想过是否可能只用一个GCP来完成这个操作?我也知道我的像素分辨率是多少米。如果您有兴趣回答,这是我的问题链接: https://gis.stackexchange.com/questions/386863/getting-geo-transforms-affine-without-a-tiff-reference-image?noredirect=1#comment633884_386863。 - salRad
1
@salRad 看起来你已经把它全部搞定了,但如果你仍然需要我的意见,请告诉我 :) - Kat
@Kat,感谢你的回答,你让我的生活变得更轻松了。对于那些想要使用jpg而不是tiff的人来说,整个过程都非常完美,但是你需要在gdal.Open中去掉gdal.GA_Update选项才能读取jpg图像!干杯 - Skarl001

2
对于您的gdal方法,只需使用带有outdataset的gdal.Warp即可,例如:
outdataset.SetProjection(srs.ExportToWkt()) 
wkt = outdataset.GetProjection() 
outdataset.SetGCPs(gcp_list,wkt)
gdal.Warp("output_name.tif", outdataset, dstSRS='EPSG:2193', format='gtiff')

这将创建一个名为output_name.tif的新文件。

最初我被srs.ExportToWkt()卡住了,收到以下错误信息:"NameError: name 'srs' is not defined"。我只需将代码中的srs更改为output_SRS.ExportToWkt(),现在该部分似乎可以运行。整个GDAL脚本现在都可以运行,并生成一个名为"image_gdal.jpg"的文件。但该文件没有地理参考和任何与之关联的世界文件。按照您的建议,我添加了gdal.Warp("output_name.tif", outdataset, dstSRS='EPSG:2193', format='gtiff'),但是找不到名为"output_name.tif"的文件——它似乎没有生成。 - Kat

0
作为对@Kat答案的补充,为了避免原始图像文件的质量损失并将nodata值设置为0,可以使用以下方法。
#Load the original file
src_ds = gdal.Open(orig_fn)

#Create tmp dataset saved in memory
driver = gdal.GetDriverByName('MEM')
tmp_ds = driver.CreateCopy('', src_ds, strict=0)

#
# ... setting GCP....
#

# Setting no data for all bands
for i in range(1, tmp_ds.RasterCount + 1):
    f = tmp_ds.GetRasterBand(i).SetNoDataValue(0)

# Saving as file
driver = gdal.GetDriverByName('GTiff')
ds = driver.CreateCopy(output_fn, tmp_ds, strict=0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接