增加天仪卫星

master
chenzenghui 2025-08-25 10:29:15 +08:00
parent d4b5539ce6
commit 7dadcfb53b
4 changed files with 378 additions and 0 deletions

View File

@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
import argparse
import os
from osgeo import gdal, osr
import numpy as np
import netCDF4 as nc
from datetime import datetime, timezone
import time
def nc2ENVIBin(nc_file_path,output_envi_path,utctime):
# Input parameters (replace these with your actual values)
time_index = -1 # Example: 0 for the first time step; adjust if needed
# Step 1: Read the NetCDF file using netCDF4
ds=None
filename = "数据/测试文件.nc"
with open(nc_file_path, 'rb') as f:
ds = nc.Dataset('in_memory', mode='r', memory=f.read())
print(f"Available variables: {list(ds.variables.keys())}") # Optional: Print variables for verification
valid_time_list=ds.variables["valid_time"][:]
for timeID in range(0,len(valid_time_list)):
# print(valid_time_list[timeID],utctime)
if valid_time_list[timeID] == utctime:
time_index = timeID
break
if time_index == -1:
return -1
else:
print(f"time_index={time_index}")
# Extract the variable data (assuming 3D: time, lat, lon)
data_U10 = ds.variables["u10"][time_index, :, :].filled(np.nan) # Handle masked values as NaN
data_V10 = ds.variables["v10"][time_index, :, :].filled(np.nan) # Handle masked values as NaN
# Extract lat and lon (adjust variable names if your file uses different ones, e.g., 'latitude', 'longitude')
lat = ds.variables['latitude'][:]
lon = ds.variables['longitude'][:]
# Calculate geotransform parameters
x_res = (lon[-1] - lon[0]) / (len(lon) - 1)
y_res = (lat[0] - lat[-1]) / (len(lat) - 1) # Note: lat often decreases north to south
top_left_x = lon[0] - x_res / 2
top_left_y = lat[0] + y_res / 2
geotransform = (top_left_x, x_res, 0, top_left_y, 0, -y_res) # Negative y_res for north-up
# Step 2: Create ENVI file using GDAL
driver = gdal.GetDriverByName('ENVI')
envi_ds = driver.Create(
output_envi_path,
data_U10.shape[1], # Width (lon)
data_U10.shape[0], # Height (lat)
2, # Single band
gdal.GDT_Float32 # Assuming float data; adjust to gdal.GDT_Float64 if needed
)
# Set geotransform and projection (EPSG:4326 for WGS84 lat/lon)
envi_ds.SetGeoTransform(geotransform)
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
envi_ds.SetProjection(srs.ExportToWkt())
# Write the data to the band
envi_band = envi_ds.GetRasterBand(1)
envi_band.SetNoDataValue(np.nan) # Set NaN as no-data value (optional)
envi_band.WriteArray(data_U10)
envi_band = envi_ds.GetRasterBand(2)
envi_band.SetNoDataValue(np.nan) # Set NaN as no-data value (optional)
envi_band.WriteArray(data_V10)
# Add ENVI-specific metadata to the header (optional, but recommended)
envi_ds.SetMetadataItem('wavelength units', 'None', 'ENVI') # Example; customize as needed
envi_ds.SetMetadataItem('data type', '4', 'ENVI') # 4 = float32; matches GDT_Float32
# Clean up
envi_ds.FlushCache()
envi_ds = None
ds.close()
print(f"Conversion complete: {output_envi_path} (with .hdr)")
def getParams():
parser = argparse.ArgumentParser()
parser.add_argument('-i','--infile',default=r'D:\风场\20250807_SAR_EC_2024年\ERA5风场\total_precipitation202410.nc', help='输入风场文件路径')
parser.add_argument('-o', '--outfile',default=r'D:\风场\20250807_SAR_EC_2024年\ERA5风场\total_precipitation202410.bin', help='输出Bin文件路径')
parser.add_argument('-t', '--time',type=int, default=2024100108,help='yyyymmddhh')
args = parser.parse_args()
return args
def timestr2utc(timeint):
timestr = str(timeint)
# 解析字符串为datetime对象默认无时区信息
dt = datetime.strptime(timestr, "%Y%m%d%H")
# 显式标记为UTC时间两种等效方式
dt_utc = dt.replace(tzinfo=timezone.utc) # 方式1使用标准库
# 或使用pytz库dt_utc = pytz.utc.localize(dt)
timestamp = time.mktime(dt_utc.timetuple())
utc_timestamp = int(timestamp) # 当前UTC时间戳秒级
print("UTC时间:", dt_utc)
print("ISO格式:", dt_utc.isoformat()) # 输出2024-08-01T02:00:00+00:00
print("UTC时间戳:", utc_timestamp) # 输出2024-08-01T02:00:00+00:00
return utc_timestamp
if __name__ == '__main__':
parser = getParams()
inNcFilePath=parser.infile
outbinpath=parser.outfile
searchTime=parser.time
print('infile=',inNcFilePath)
print('outfile=',outbinpath)
time_utc=timestr2utc(searchTime)
nc2ENVIBin(inNcFilePath,outbinpath,time_utc)

View File

@ -0,0 +1,41 @@
import argparse
import os
from osgeo import gdal, osr
import numpy as np
def tiff_to_bin_with_metadata(tiff_path, bin_path):
# 转换格式为ENVI格式的BIN自动生成.hdr元数据文件
options = gdal.TranslateOptions(
format='ENVI', # ENVI格式生成.hdr文件存储地理信息
)
# 临时输出ENVI格式文件含.hdr
# temp_path = bin_path.replace('.bin', '_temp.bin')
gdal.Translate(bin_path, tiff_path, options=options)
# # 重命名文件并清理临时文件
# os.rename(temp_path, bin_path) # 主数据文件
# os.rename(temp_path + '.hdr', bin_path + '.hdr') # 元数据文件
# 可选:额外保存投影文件(.prj
dataset = gdal.Open(tiff_path)
if dataset.GetProjection():
with open(bin_path.replace('.bin', '.prj'), 'w') as f_prj:
f_prj.write(dataset.GetProjection())
dataset = None
def getParams():
parser = argparse.ArgumentParser()
parser.add_argument('-i','--infile',default=r'K:\风场数据\样例风场数据\4254_20240801095415\s1a-iw-grd-vv-20240801t095415-20240801t095444-055018-06b3e9-001-DB-GEO.tif', help='输入原始tiff')
parser.add_argument('-o', '--outfile',default=r'K:\风场数据\样例风场数据\4254_20240801095415\s1a-iw-grd-vv-20240801t095415-20240801t095444-055018-06b3e9-001-DB-GEO.bin', help='输出Bin文件路径')
args = parser.parse_args()
return args
if __name__ == '__main__':
parser = getParams()
intiffPath=parser.infile
outbinPath=parser.outfile
print('infile=',intiffPath)
print('outfile=',outbinPath)
tiff_to_bin_with_metadata(intiffPath, outbinPath)
print("convert tiff to bin file successfully")

View File

@ -0,0 +1,123 @@
import argparse
import os
from osgeo import gdal, osr
import numpy as np
os.environ['GDAL_CACHEMAX'] = '2048'
def resample_to_match(image_A_path, image_B_path, output_path, resample_method=gdal.GRA_Bilinear):
"""
将图像A重采样至与图像B相同的坐标网格和分辨率
:param image_A_path: 待重采样的图像A路径
:param image_B_path: 参考图像B路径
:param output_path: 输出文件路径
:param resample_method: 重采样方法默认双线性插值
"""
gdal.AllRegister()
# 1. 打开参考图像B获取其空间参数
ds_B = gdal.Open(image_B_path, gdal.GA_ReadOnly)
if ds_B is None:
raise RuntimeError("无法打开参考图像B")
# 提取B的投影、仿射变换、尺寸和波段数
proj_B = ds_B.GetProjection()
geotrans_B = ds_B.GetGeoTransform()
width_B = ds_B.RasterXSize
height_B = ds_B.RasterYSize
bands_B = ds_B.RasterCount
data_type_B = ds_B.GetRasterBand(1).DataType
ds_A = gdal.Open(image_A_path, gdal.GA_ReadOnly)
if ds_A is None:
raise RuntimeError("无法打开输入图像A")
bands_A=ds_A.RasterCount
# 2. 创建输出文件完全复制B的空间参数
driver = gdal.GetDriverByName('ENVI')
ds_out = driver.Create(
output_path,
width_B, height_B,
bands_A,
data_type_B
)
ds_out.SetGeoTransform(geotrans_B)
ds_out.SetProjection(proj_B)
# 3. 执行重采样
# 配置WarpOptions参数关键修改点
warp_opts = gdal.WarpOptions(
srcSRS=ds_A.GetProjection(), # 输入投影
dstSRS=proj_B, # 目标投影
resampleAlg=resample_method, # 重采样方法如gdal.GRA_Bilinear
warpMemoryLimit=2 * 1024**3, # 单块内存限制为2GB单位字节
# 分块处理相关参数
multithread=True, # 启用多线程加速
)
# 执行Warp操作自动分块处理
gdal.Warp(
ds_out, # 输出数据集
ds_A, # 输入数据集
options=warp_opts
)
# 4. 释放资源
ds_A = ds_B = ds_out = None
print(f"重采样完成,结果已保存至: {output_path}")
# 4. 释放资源
ds_A = ds_B = ds_out = None
print(f"重采样完成,结果已保存至: {output_path}")
def getParams():
parser = argparse.ArgumentParser()
parser.add_argument('-i','--infile',default=r'F:\Data\SAR\IDL\SAR_EC_20240801\total_precipitation2024080110.bin', help='输入文件')
parser.add_argument('-o', '--outfile',default=r'F:\Data\SAR\IDL\SAR_EC_20240801\total_precipitation2024080110_resample.bin', help='输出Bin文件路径')
parser.add_argument('-r', '--reffile',default=r'F:\Data\SAR\IDL\SAR_EC_20240801\4254-DB-GEO.tif', help='参考影像')
group = parser.add_mutually_exclusive_group()
group.add_argument(
'--nearest',
action='store_const',
const='nearest',
dest='method',
help='启用最邻近插值(默认)'
)
group.add_argument(
'--bilinear',
action='store_const',
const='bilinear',
dest='method',
help='启用双线性插值'
)
parser.set_defaults(method='nearest')
args = parser.parse_args()
return args
if __name__ == '__main__':
parser = getParams()
intiffPath=parser.infile
outbinPath=parser.outfile
refbinPath=parser.reffile
methodstr=parser.method
print('infile=',intiffPath)
print('outfile=',outbinPath)
print('reffile=',refbinPath)
print('method=',methodstr)
resamplemethodgdal=None
if methodstr == 'nearest':
resamplemethodgdal=gdal.GRA_NearestNeighbour
elif methodstr == 'bilinear':
resamplemethodgdal=gdal.GRA_Bilinear
else:
resamplemethodgdal = gdal.GRA_NearestNeighbour
resample_to_match(
image_A_path=intiffPath,
image_B_path=refbinPath,
output_path=outbinPath,
resample_method=resamplemethodgdal # 可选gdal.GRA_NearestNeighbour最邻近
)
print("resample to match successfully")

View File

@ -0,0 +1,97 @@
import rasterio
from rasterio.windows import Window
import geopandas as gpd
from shapely.geometry import box
import numpy as np
import os
# 参数设置
image_path = 'path/to/your/image.tif' # 替换为您的影像路径20000x20000
shapefile_path = 'path/to/your/shapefile.shp' # 替换为您的图斑Shapefile路径
output_dir = 'path/to/output/tiles' # 输出切片目录
tile_size = 1024 # 固定切片大小
max_overlap_ratio = 0.2 # 重叠小于20%
min_step = int(tile_size * (1 - max_overlap_ratio)) # 最小步长 ≈820
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 读取影像
with rasterio.open(image_path) as src:
image_width, image_height = src.width, src.height
assert image_width == 20000 and image_height == 20000, "影像大小不匹配"
transform = src.transform # 地理变换矩阵
# 读取图斑数据假设CRS一致
gdf = gpd.read_file(shapefile_path)
# 确保图斑CRS与影像一致如果不一致需转换gdf = gdf.to_crs(src.crs)
# 初始化切片列表,避免重叠过多
generated_windows = []
for idx, row in gdf.iterrows():
geom = row.geometry # 获取单个图斑多边形
# 计算图斑的边界框 (minx, miny, maxx, maxy) - 像素坐标
minx, miny, maxx, maxy = geom.bounds
bbox_width = maxx - minx
bbox_height = maxy - miny
# 如果图斑太大无法放入单个1024x1024切片需处理这里简单跳过您可修改
if bbox_width > tile_size or bbox_height > tile_size:
print(f"图斑 {idx} 太大 ({bbox_width}x{bbox_height}),跳过或需多切片处理")
continue
# 计算覆盖完整图斑的最小窗口居中扩展到1024x1024
center_x = (minx + maxx) / 2
center_y = (miny + maxy) / 2
half_tile = tile_size / 2
win_minx = max(0, center_x - half_tile)
win_miny = max(0, center_y - half_tile)
win_maxx = min(image_width, center_x + half_tile)
win_maxy = min(image_height, center_y + half_tile)
# 调整以确保正好1024x1024如果边界不足padding或调整
if win_maxx - win_minx < tile_size:
win_minx = max(0, win_maxx - tile_size)
if win_maxy - win_miny < tile_size:
win_miny = max(0, win_maxy - tile_size)
proposed_window = Window(win_minx, win_miny, tile_size, tile_size)
# 检查与现有窗口的重叠,确保<20%
too_much_overlap = False
for existing_win in generated_windows:
# 计算重叠区域
overlap_x = max(0, min(win_minx + tile_size, existing_win.col_off + tile_size) - max(win_minx, existing_win.col_off))
overlap_y = max(0, min(win_miny + tile_size, existing_win.row_off + tile_size) - max(win_miny, existing_win.row_off))
overlap_area = overlap_x * overlap_y
if overlap_area > (tile_size * tile_size * max_overlap_ratio):
too_much_overlap = True
break
if too_much_overlap:
# 如果重叠太大,调整位置(这里简单跳过,您可实现更复杂的调整,如偏移步长)
print(f"图斑 {idx} 的窗口重叠过多,跳过或调整")
continue
# 添加到列表
generated_windows.append(proposed_window)
# 裁剪并保存切片
tile_data = src.read(window=proposed_window)
tile_meta = src.meta.copy()
tile_meta.update({
'width': proposed_window.width,
'height': proposed_window.height,
'transform': rasterio.windows.transform(proposed_window, src.transform)
})
output_path = os.path.join(output_dir, f'tile_{idx}.tif')
with rasterio.open(output_path, 'w', **tile_meta) as dst:
dst.write(tile_data)
print(f"生成切片 {output_path},覆盖图斑 {idx}")
print(f"总共生成 {len(generated_windows)} 个切片")
# 注意:这个代码确保每个切片包含至少一个完整图斑,但可能有图斑被多个切片覆盖(如果重叠允许)。如果需要覆盖所有图斑的最优 tiling请提供更多细节。