按照规定顺序融合tif,需要tif路径有序写入列表。
使用qgis打开各个影像,调整tif顺序,如下图所示选中所有文件(或选中需要合并的tif图层)导出为图层定义文件(.qlr文件),放到与当前工程文件(.qgz文件)相同目录下。(无序融合tif,直接os.listdir)
import os
import sys
import rasterio
from rasterio.merge import merge
from rasterio.warp import calculate_default_transform, reproject, Resampling
from rasterio.crs import CRS
from rasterio import Affine
def mk_dir(path,a=0):
if os.path.exists(path):
path=mk_dir(path.replace(f"_({a})","")+f"_({a+1})",a=a+1)
else:
os.makedirs(path)
return path
def remove_dir(dir):
import shutil
if os.path.exists(dir):
shutil.rmtree(dir)
def get_tifpath_list(folder):
path_list=os.listdir(folder)
tifpath_list=[folder+os.sep+i for i in path_list if ".tif"==i[-4:]]
return tifpath_list
# 重投影,坐标系修改
def raster_resamping(path,save,_crs=False,ac=False):
"""
:param path: 原始tif
:param save: 输出tif
:param _crs: 坐标系,默认False按照原始图像的坐标系
:param ac: 输出分辨率(m),默认False按照原始图像分辨率
:return:
"""
if os.path.exists(save):
print("文件已存在!!!",save)
return save
if _crs:
dst_crs = CRS.from_epsg(_crs)
with rasterio.open(path) as src:
if not _crs:
dst_crs = src.crs
if not ac :
ac=Affine.to_gdal(src.transform)[1]
if src.crs == dst_crs and ac==Affine.to_gdal(src.transform)[1]: # 坐标系和分辨率没有变化,跳过
print("目标tif,与原tif一致,end!",path)
return path
try:
transform, width, height = calculate_default_transform(
src.crs,
dst_crs,
src.width,
src.height,
resolution=(ac,ac), # 输出图像分辨率,单位m
*src.bounds)
except:
print("计算错误!end!")
return # 计算错误跳过这张tif
kwargs = src.meta.copy()
kwargs.update(
{"crs": dst_crs, "transform": transform, "width": width, "height": height, "compress": 'lzw'}
)
with rasterio.open(save, "w", **kwargs) as dst:
for i in range(1, src.count + 1):
reproject(
source=rasterio.band(src, i),
destination=rasterio.band(dst, i),
src_transform=src.transform,
src_crs=src.crs,
dst_transform=transform,
dst_crs=dst_crs,
resampling=Resampling.nearest
)
print("重投影已完成!!!",save)
return save
# 读取.qlr文件获取tif顺序
def read_qlr(path):
path_dirname=os.path.dirname(os.path.abspath(path))
with open(path, "r", encoding='UTF-8') as f:
res = f.read()
from bs4 import BeautifulSoup
soup = BeautifulSoup(res, 'html.parser')
all = soup.find_all('layer-tree-layer')
# 文件列表
tifpath_list = []
for li_all in all:
tif_path = li_all.attrs["source"]
if tif_path[-4:] == ".tif":
if not os.path.exists(tif_path):
tif_path=os.path.join(path_dirname,tif_path.split("./")[-1] ) # 将相对路径改为绝对路径
tifpath_list.append(tif_path)
return tifpath_list
def tif_stitch(tifpath_list, save):
print(f"{len(tifpath_list)}张图,开始拼接tif!!!!!")
src_files_to_mosaic = [rasterio.open(i) for i in tifpath_list]
dst_data, out_trans = merge(src_files_to_mosaic)
out_meta = src_files_to_mosaic[0].meta.copy()
out_meta.update({"driver": "GTiff",
"height": dst_data.shape[1],
"width": dst_data.shape[2],
"transform": out_trans
}
)
# 保存文件
with rasterio.open(save, "w", **out_meta) as dest:
dest.write(dst_data)
def main(path, save,_crs=False,pix=False):
if os.path.exists(save):
print("文件已存在!")
return None
# 读取.qlr文件获取tif顺序
tifpath_list=read_qlr(path)
# tifpath_list=get_tifpath_list(path)
print(f"共{len(tifpath_list)}张图需要融合")
# 重投影、坐标转换
temp_files= mk_dir('temp')
tifpath_list=[raster_resamping(i,f"{temp_files}/{os.path.basename(i)}",_crs=_crs, ac=pix) for i in tifpath_list if raster_resamping(i,f"{temp_files}/{os.path.basename(i)}",_crs=_crs, ac=pix) !=None]
# 拼接tif
tif_stitch(tifpath_list, save)
# # 删除过程文件
# remove_dir(temp_files)
print("融合成功!!!!!!")
if __name__ == '__main__':
# path = sys.argv[1] # .qlr文件路径
# save = sys.argv[2] # 保存文件地址
path = r"D:\Desktop\demo_tif\demo.qlr"
save = r"merge_demo.tif"
main(path, save,_crs=3857,pix=0.1)