python gdal 简单实现图像拼接

利用gdal将下列示例影像合并
在这里插入图片描述

一、读取影像

利用gdal读取遥感影像

from osgeo import gdal

def read_img(filename):
    dataset = gdal.Open(filename)  # 打开文件
    if dataset == None:
        raise Exception(f"cant find/open {filename}")
    im_width = dataset.RasterXSize  # 栅格矩阵的列数
    im_height = dataset.RasterYSize  # 栅格矩阵的行数
    im_Band = dataset.RasterCount  # 栅格矩阵的波段数

    im_geotrans = dataset.GetGeoTransform()
    im_proj = dataset.GetProjection()
    im_data = dataset.ReadAsArray(0, 0, im_width, im_height)  # 将数据写成数组,对应栅格矩阵

    del dataset  # 关闭对象,文件dataset
    return im_proj, im_geotrans, im_data, im_width, im_height, im_Band

二、横向合并矩阵

利用numpy合并矩阵

    im_proj, im_geotrans, im_data1, im_width, im_height, im_Band = read_img(filepath1)
    _, _, im_data2, _, _, _ = read_img(filepath2)
    _, _, im_data3, _, _, _ = read_img(filepath3)
    _, _, im_data4, _, _, _ = read_img(filepath4)
    _, _, im_data5, _, _, _ = read_img(filepath5)
    im_data = np.concatenate((im_data1, im_data2, im_data3, im_data4, im_data5), axis=2)
    print(f"im_data1.shape:{im_data1.shape}")
    print(f"im_data2.shape:{im_data2.shape}")
    print(f"im_data3.shape:{im_data3.shape}")
    print(f"im_data4.shape:{im_data4.shape}")
    print(f"im_data5.shape:{im_data5.shape}")
    print(f"im_data.shape :{im_data.shape}")

输出结果

im_data1.shape:(4, 1000, 1000)
im_data2.shape:(4, 1000, 1000)
im_data3.shape:(4, 1000, 1000)
im_data4.shape:(4, 1000, 1000)
im_data5.shape:(4, 1000, 1000)
im_data.shape :(4, 1000, 5000)

三、利用相片坐标计算坐标位置

根据仿射变换参数计算坐标位置

def imagexy2geo(im_geotrans, row, col):
    """
    相片坐标计算坐标位置
    :param im_geotrans:图像放射变换参数
    :param row: 行数
    :param col: 列数
    :return: 坐标位置
    """
    px = im_geotrans[0] + col * im_geotrans[1] + row * im_geotrans[2]
    py = im_geotrans[3] + col * im_geotrans[4] + row * im_geotrans[5]
    return [px, py]

四、计算仿射变换参数

根据新坐标位置重算仿射变换参数

def setGeotrans(im_geotrans, row, col):
    """
    根据影像大小重算仿射变换参数
    :param im_geotrans: 
    :param row: 行数
    :param col: 列数
    :return: 仿射变换参数
    """
    coords00 = imagexy2geo(im_geotrans, 0, 0)
    coords01 = imagexy2geo(im_geotrans, row, 0)
    coords10 = imagexy2geo(im_geotrans, 0, col)

    trans = [0 for i in range(6)]
    trans[0] = coords00[0]
    trans[3] = coords00[1]
    trans[2] = (coords01[0] - trans[0]) / row
    trans[5] = (coords01[1] - trans[3]) / row
    trans[1] = (coords10[0] - trans[0]) / col
    trans[4] = (coords10[1] - trans[3]) / col
    return trans

五、输出影像

根据新坐标位置重算仿射变换参数

DType2GDAL = {"uint8": gdal.GDT_Byte,
              "uint16": gdal.GDT_UInt16,
              "int16": gdal.GDT_Int16,
              "uint32": gdal.GDT_UInt32,
              "int32": gdal.GDT_Int32,
              "float32": gdal.GDT_Float32,
              "float64": gdal.GDT_Float64,
              "cint16": gdal.GDT_CInt16,
              "cint32": gdal.GDT_CInt32,
              "cfloat32": gdal.GDT_CFloat32,
              "cfloat64": gdal.GDT_CFloat64}


def write_img(filename, im_proj, im_geotrans, im_data):
    # 判断栅格数据的数据类型
    if im_data.dtype.name in DType2GDAL:
        datatype = DType2GDAL[im_data.dtype.name]
    else:
        datatype = gdal.GDT_Float32
    # 判读数组维数
    if len(im_data.shape) == 3:
        im_bands, im_height, im_width = im_data.shape
    else:
        im_bands, (im_height, im_width) = 1, im_data.shape
    # 创建文件
    if not pathlib.Path(filename).parent.exists():
        pathlib.Path(filename).parent.mkdir(parents=True, exist_ok=True)
    driver = gdal.GetDriverByName("GTiff")  # 数据类型必须有,因为要计算需要多大内存空间
    dataset = driver.Create(filename, im_width, im_height, im_bands, datatype)

    dataset.SetGeoTransform(im_geotrans)  # 写入仿射变换参数
    dataset.SetProjection(im_proj)  # 写入投影
    if im_bands == 1:
        dataset.GetRasterBand(1).WriteArray(im_data)  # 写入数组数据
    else:
        for i in range(im_bands):
            dataset.GetRasterBand(i + 1).WriteArray(im_data[i])
    del dataset


完整代码

# -*- coding: utf-8 -*-
"""
 @ time: 2022/11/11 13:49
 @ file:
 @ author: QYD2001
"""
import pathlib

import numpy as np
from osgeo import gdal

DType2GDAL = {"uint8": gdal.GDT_Byte,
              "uint16": gdal.GDT_UInt16,
              "int16": gdal.GDT_Int16,
              "uint32": gdal.GDT_UInt32,
              "int32": gdal.GDT_Int32,
              "float32": gdal.GDT_Float32,
              "float64": gdal.GDT_Float64,
              "cint16": gdal.GDT_CInt16,
              "cint32": gdal.GDT_CInt32,
              "cfloat32": gdal.GDT_CFloat32,
              "cfloat64": gdal.GDT_CFloat64}


def write_img(filename, im_proj, im_geotrans, im_data):
    # 判断栅格数据的数据类型
    if im_data.dtype.name in DType2GDAL:
        datatype = DType2GDAL[im_data.dtype.name]
    else:
        datatype = gdal.GDT_Float32
    # 判读数组维数
    if len(im_data.shape) == 3:
        im_bands, im_height, im_width = im_data.shape
    else:
        im_bands, (im_height, im_width) = 1, im_data.shape
    # 创建文件
    if not pathlib.Path(filename).parent.exists():
        pathlib.Path(filename).parent.mkdir(parents=True, exist_ok=True)
    driver = gdal.GetDriverByName("GTiff")  # 数据类型必须有,因为要计算需要多大内存空间
    dataset = driver.Create(filename, im_width, im_height, im_bands, datatype)

    dataset.SetGeoTransform(im_geotrans)  # 写入仿射变换参数
    dataset.SetProjection(im_proj)  # 写入投影
    if im_bands == 1:
        dataset.GetRasterBand(1).WriteArray(im_data)  # 写入数组数据
    else:
        for i in range(im_bands):
            dataset.GetRasterBand(i + 1).WriteArray(im_data[i])
    del dataset


def read_img(filename):
    dataset = gdal.Open(filename)  # 打开文件
    if dataset == None:
        raise Exception(f"cant find/open {filename}")
    im_width = dataset.RasterXSize  # 栅格矩阵的列数
    im_height = dataset.RasterYSize  # 栅格矩阵的行数
    im_Band = dataset.RasterCount  # 栅格矩阵的行数

    im_geotrans = dataset.GetGeoTransform()
    im_proj = dataset.GetProjection()
    im_data = dataset.ReadAsArray(0, 0, im_width, im_height)  # 将数据写成数组,对应栅格矩阵

    del dataset  # 关闭对象,文件dataset
    return im_proj, im_geotrans, im_data, im_width, im_height, im_Band


def imagexy2geo(im_geotrans, row, col):
    """
    相片坐标计算坐标位置
    :param im_geotrans:图像放射变换参数
    :param row: 行数
    :param col: 列数
    :return: 坐标位置
    """
    px = im_geotrans[0] + col * im_geotrans[1] + row * im_geotrans[2]
    py = im_geotrans[3] + col * im_geotrans[4] + row * im_geotrans[5]
    return [px, py]


def setGeotrans(im_geotrans, row, col):
    """
    根据影像大小重算仿射变换参数
    :param im_geotrans:
    :param row:
    :param col:
    :return: 仿射变换参数
    """
    coords00 = imagexy2geo(im_geotrans, 0, 0)
    coords01 = imagexy2geo(im_geotrans, row, 0)
    coords10 = imagexy2geo(im_geotrans, 0, col)

    trans = [0 for i in range(6)]
    trans[0] = coords00[0]
    trans[3] = coords00[1]
    trans[2] = (coords01[0] - trans[0]) / row
    trans[5] = (coords01[1] - trans[3]) / row
    trans[1] = (coords10[0] - trans[0]) / col
    trans[4] = (coords10[1] - trans[3]) / col
    return trans


if __name__ == '__main__':
    filepath1 = r"E:\RsData\1108\1m\1m\LNPJ210912_GF2PMS0005882472_001_001.tif"
    filepath2 = r"E:\RsData\1108\1m\1m\LNPJ210912_GF2PMS0005882472_001_002.tif"
    filepath3 = r"E:\RsData\1108\1m\1m\LNPJ210912_GF2PMS0005882472_001_003.tif"
    filepath4 = r"E:\RsData\1108\1m\1m\LNPJ210912_GF2PMS0005882472_001_004.tif"
    filepath5 = r"E:\RsData\1108\1m\1m\LNPJ210912_GF2PMS0005882472_001_005.tif"
    outpath = r"E:\RsData\1108\1m\1m\LNPJ210912_GF2PMS0005882472_001.tif"

    im_proj, im_geotrans, im_data1, im_width, im_height, im_Band = read_img(filepath1)
    _, _, im_data2, _, _, _ = read_img(filepath2)
    _, _, im_data3, _, _, _ = read_img(filepath3)
    _, _, im_data4, _, _, _ = read_img(filepath4)
    _, _, im_data5, _, _, _ = read_img(filepath5)
    im_data = np.concatenate((im_data1, im_data2, im_data3, im_data4, im_data5), axis=2)
    print(f"im_data1.shape:{im_data1.shape}")
    print(f"im_data2.shape:{im_data2.shape}")
    print(f"im_data3.shape:{im_data3.shape}")
    print(f"im_data4.shape:{im_data4.shape}")
    print(f"im_data5.shape:{im_data5.shape}")
    print(f"im_data.shape :{im_data.shape}")

    geotrans = setGeotrans(im_geotrans, im_data.shape[0], im_data.shape[1])
    write_img(outpath, im_proj, geotrans, im_data)


输出结果
在这里插入图片描述
圆满完成任务@-@

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python GDAL图像拼接是指将多张地理信息系统(GIS)图像文件合并为一张更大的地图。这个过程涉及到将多个地图投影成同一个坐标系、大小和像素分辨率。首先需要用GDAL库读取原始图像文件,然后将它们转换为统一格式,并实行坐标系统的转换,使它们都以同样的方式进行渲染。接着需要确定最终拼接图像的大小和分辨率,并使用GDAL库核实这些参数。最后,将各个图像拼接在一起,生成一个全新的大图。这个过程可以使用GDAL库的“gdal_merge.py”模块或者“Dataset.ReadAsArray()”方法来执行。合并完成后,还可以使用Python脚本对图像进行进一步的剪裁、裁剪或图像矢量化。 总的来说,Python GDAL图像拼接是一项复杂的工作,需要深入理解GDAL库的功能和图像处理技术。如果你想进行GIS图像拼接和处理,这个库会是一个非常有用的资源。它可以让你快速有效地合并、处理大量的地图数据,并生成一张完整的高清地图。 ### 回答2: Python是一种非常方便的编程语言,用于处理数据和图像非常方便,为了实现图像拼接功能,Gdal库是一个非常好的选择。Gdal是c++编写的一种开放源代码的软件库,主要用于在读写常见的栅格空间数据格式的文件。通过Gdal库,我们可以方便地读取,处理和操作图像,可以实现图像拼接等各种功能。 以下是用Python GDAL实现图像拼接的一般步骤: 1. 打开要拼接的两个或更多图像文件。我们可以使用gdal_open函数来打开图像文件。 2. 确定合成图像的大小和位置。在图像处理过程中,必须指定新图像的大小和位置以进行合成。 3. 确定输入图像(或“成像区域”)的范围。在合成图像时,必须选择每个输入图像的范围。我们可以使用gdal_translate函数执行此操作。 4. 映射输入图像,以便它们适合于合成图像的大小和位置。这可以通过gdal_warp函数来执行。 5. 对图像执行任何必要的处理。例如,周边均衡化、亮度、色调等。一般在这个步骤中,还需要进行颜色匹配。 6. 合成图像。使用gdal_merge函数将已映射,并经过处理后的图像合成。 7. 保存输出图像。使用gdal_translate函数或其他类似函数输出新文件。 在Python中使用gdal库,我们还可以使用numpy库来处理图像数据,matplotlib库来显示图像,以及图像处理方面的其它Python库。Python GDAL库的使用需要有一定的基础,同时掌握相关的图像处理技术和方法,在实际应用中,需要对图像的处理逻辑进行合理的规划和设计。 ### 回答3: Python GDAL是一个处理地理空间数据的强大工具,可以帮助我们实现图像拼接图像拼接是将多个图像合并成一个大型图像的处理过程,用于制作地图和卫星图像图像拼接的基本原理是确定每个图像的边界,将它们按照一定的规则排列在一起,并保持彼此之间的连续性。常用的技术是通过遮罩过滤掉图像背景的没有用部分,然后进行重叠和透明度混合等操作。 下面的步骤将指导您如何使用Python GDAL完成图像拼接: 1. 导入必要的库 使用Python GDAL时,需要导入一些必要的库,如numpy、gdal和osgeo,以便能够处理地理空间数据。 ```python import numpy as np from osgeo import gdal from osgeo import osr ``` 2. 读取图像 使用GDAL打开多个图像,利用numpy将其转换为数组,再根据需要对其进行处理。 ```python ds = gdal.Open('image1.tif') image1 = np.array(ds.GetRasterBand(1).ReadAsArray()) ds = gdal.Open('image2.tif') image2 = np.array(ds.GetRasterBand(1).ReadAsArray()) ``` 3. 确定图像边界 对于每一个图像,使用GDAL获取其边界和投影信息,然后将其转换为我们需要的坐标系统。在这里,我们使用欧气射投影(Mercator projection)。 ```python geo_transform = ds.GetGeoTransform() proj = ds.GetProjection() #获取左上角和右下角的坐标 ul = (geo_transform[0], geo_transform[3]) lr = (geo_transform[0] + geo_transform[1] * ds.RasterXSize, geo_transform[3] + geo_transform[5] * ds.RasterYSize) #将边界转换为Mercator projection src_srs = osr.SpatialReference() src_srs.ImportFromWkt(proj) tgt_srs = src_srs.CloneGeogCS() coord_trans = osr.CoordinateTransformation(src_srs, tgt_srs) ul_lon, ul_lat, _ = coord_trans.TransformPoint(ul[0], ul[1]) lr_lon, lr_lat, _ = coord_trans.TransformPoint(lr[0], lr[1]) ``` 4. 缩放和重采样 将较小的图像缩放到与较大的图像相同的大小,同时使用重采样功能来确保图像缩放后的质量。 ```python #将image2缩放到image1的大小 resampled_image2 = np.zeros_like(image1) gdal.ReprojectImage(ds, gdal.Open('image1.tif'), proj, proj, gdal.GRA_NearestNeighbour, callback = gdal.TermProgress_nocb) resampled_image2 = np.array(ds.GetRasterBand(1).ReadAsArray()) ``` 5. 重叠和混合 计算每幅图像的重叠区域以及透明度,然后将它们混合在一起。我们可以使用numpy的where()函数生成一个遮罩来实现这个操作。 ```python #获取图像重叠区域 overlap = (ul_lon < lr_lon) and (ul_lat > lr_lat) if overlap: #转换投影并计算图像重叠区域和透明度 left, bottom, right, top = (ul_lon, lr_lat, lr_lon, ul_lat) overlapped_image1 = image1[(image1_lon < right) & (image1_lon > left)] overlapped_resampled_image2 = resampled_image2[(resampled_image2_lon > left) & (resampled_image2_lon < right)] blend_alpha = np.zeros_like(image1) blend_alpha[(image1_lat < top)&(image1_lat > bottom)&(resampled_image2_lat < top)&(resampled_image2_lat > bottom)] = 1.0 #将图像进行混合,alpha是透明度 blended_image = np.where(blend_alpha == 1.0, resampled_image2, image1) alpha = np.where(blended_image == resampled_image2, blend_alpha, 1.0 - blend_alpha) else: blended_image = image1 ``` 6. 输出结果 当完成图像拼接时,可以使用GDAL将其保存为一个新的tif文件,以供以后使用。 ```python driver = gdal.GetDriverByName('GTiff') outdata = driver.Create('merged_image.tif', len(image1_lon), len(image1_lat), 1, gdal.GDT_Float32) outdata.SetProjection(src_srs.ExportToWkt()) outdata.SetGeoTransform(geo_transform) outdata.GetRasterBand(1).WriteArray(blended_image) outdata = None ``` 通过以上步骤,我们就可以使用Python GDAL实现图像拼接。这是一个非常实用的技术,尤其对于GIS和遥感数据的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值