131 lines
4.1 KiB
Python
131 lines
4.1 KiB
Python
|
|
"""
|
|||
|
|
掩膜tif文件的ROI区域并保存
|
|||
|
|
|
|||
|
|
输入: tif文件路径, roi文件路径(shp/geojson等)
|
|||
|
|
输出: 掩膜后的tif文件
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import argparse
|
|||
|
|
import numpy as np
|
|||
|
|
import rasterio
|
|||
|
|
from rasterio.mask import mask
|
|||
|
|
from rasterio.features import shapes
|
|||
|
|
import geopandas as gpd
|
|||
|
|
# from shapely.geometry import shape
|
|||
|
|
import logging
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def mask_tif_by_roi(tif_path: str, roi_path: str, output_path: str = None,
|
|||
|
|
nodata_value: float = None):
|
|||
|
|
"""
|
|||
|
|
使用ROI文件掩膜TIF文件
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
tif_path: 输入TIF文件路径
|
|||
|
|
roi_path: ROI文件路径(shp/geojson等)
|
|||
|
|
output_path: 输出文件路径,如果为None则自动生成
|
|||
|
|
nodata_value: nodata值,如果为None则使用原始文件的nodata值
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
str: 输出文件路径
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
tif_path = Path(tif_path)
|
|||
|
|
roi_path = Path(roi_path)
|
|||
|
|
|
|||
|
|
# 检查输入文件存在性
|
|||
|
|
if not tif_path.exists():
|
|||
|
|
raise FileNotFoundError(f"TIF文件不存在: {tif_path}")
|
|||
|
|
if not roi_path.exists():
|
|||
|
|
raise FileNotFoundError(f"ROI文件不存在: {roi_path}")
|
|||
|
|
|
|||
|
|
# 自动生成输出路径
|
|||
|
|
if output_path is None:
|
|||
|
|
output_path = tif_path.parent / f"{tif_path.stem}_masked{tif_path.suffix}"
|
|||
|
|
else:
|
|||
|
|
output_path = Path(output_path)
|
|||
|
|
|
|||
|
|
logger.info(f"开始处理: {tif_path.name}")
|
|||
|
|
logger.info(f"ROI文件: {roi_path.name}")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 读取ROI文件
|
|||
|
|
logger.info("读取ROI文件...")
|
|||
|
|
gdf = gpd.read_file(roi_path)
|
|||
|
|
|
|||
|
|
if gdf.empty:
|
|||
|
|
logger.warning("ROI文件为空,直接复制原文件")
|
|||
|
|
# 直接复制原文件
|
|||
|
|
import shutil
|
|||
|
|
shutil.copy2(tif_path, output_path)
|
|||
|
|
return str(output_path)
|
|||
|
|
|
|||
|
|
# 转换为GeoJSON格式的几何对象
|
|||
|
|
geometries = gdf.geometry.tolist()
|
|||
|
|
logger.info(f"找到 {len(geometries)} 个ROI几何对象")
|
|||
|
|
|
|||
|
|
# 读取并掩膜TIF
|
|||
|
|
logger.info("读取并掩膜TIF文件...")
|
|||
|
|
with rasterio.open(tif_path) as src:
|
|||
|
|
# 使用ROI掩膜 - 保留ROI以外的区域(ROI区域设为nodata)
|
|||
|
|
masked_data, masked_transform = mask(
|
|||
|
|
src,
|
|||
|
|
geometries,
|
|||
|
|
crop=False, # 不裁剪,保持原始尺寸
|
|||
|
|
invert=True, # 反转:ROI区域设为nodata,ROI以外保留
|
|||
|
|
nodata=nodata_value if nodata_value is not None else src.nodata
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 更新元数据
|
|||
|
|
out_meta = src.meta.copy()
|
|||
|
|
out_meta.update({
|
|||
|
|
"driver": "GTiff",
|
|||
|
|
"height": masked_data.shape[1],
|
|||
|
|
"width": masked_data.shape[2],
|
|||
|
|
"transform": masked_transform,
|
|||
|
|
"nodata": nodata_value if nodata_value is not None else src.nodata
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# 保存结果
|
|||
|
|
logger.info(f"保存掩膜结果到: {output_path.name}")
|
|||
|
|
with rasterio.open(output_path, "w", **out_meta) as dest:
|
|||
|
|
dest.write(masked_data)
|
|||
|
|
|
|||
|
|
logger.info("处理完成!")
|
|||
|
|
return str(output_path)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"处理失败: {str(e)}")
|
|||
|
|
raise
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
parser = argparse.ArgumentParser(description="使用ROI文件掩膜TIF文件")
|
|||
|
|
parser.add_argument("tif_path", help="输入TIF文件路径")
|
|||
|
|
parser.add_argument("roi_path", help="ROI文件路径 (shp/geojson等)")
|
|||
|
|
parser.add_argument("-o", "--output", help="输出文件路径 (可选,默认自动生成)")
|
|||
|
|
parser.add_argument("-n", "--nodata", type=float, help="nodata值 (可选,默认使用原文件nodata)")
|
|||
|
|
|
|||
|
|
args = parser.parse_args()
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
output_path = mask_tif_by_roi(
|
|||
|
|
args.tif_path,
|
|||
|
|
args.roi_path,
|
|||
|
|
args.output,
|
|||
|
|
args.nodata
|
|||
|
|
)
|
|||
|
|
print(f"成功完成!输出文件: {output_path}")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"错误: {e}")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
exit(main())
|