【20251203】存档

复制代码
# encoding=utf-8
from osgeo import gdal
import re
import numpy as np
import os
import xml.etree.ElementTree as ET
import warnings
from osgeo.gdalconst import GDT_Float32

warnings.filterwarnings('ignore')


def Get_File_Name(pathlog):
    xmlfile = None
    for f_name in os.listdir(pathlog):
        if f_name.endswith('.meta.xml'):
            print(f"找到元数据文件: {f_name}")
            xmlfile = os.path.join(pathlog, f_name)
            break

    if xmlfile is None:
        raise FileNotFoundError("未找到.meta.xml文件")

    image_fn = []
    for f_name in os.listdir(pathlog):
        if f_name.endswith('.tiff') or f_name.endswith('.TIFF'):
            print(f"找到图像文件: {f_name}")
            image_fn.append(os.path.join(pathlog, f_name))

    HH = []
    HV = []
    VH = []
    VV = []

    for image_path in image_fn:
        image_name = os.path.basename(image_path).upper()
        if '_HH_' in image_name or '_HH.' in image_name:
            HH = image_path
        elif '_HV_' in image_name or '_HV.' in image_name:
            HV = image_path
        elif '_VH_' in image_name or '_VH.' in image_name:
            VH = image_path
        elif '_VV_' in image_name or '_VV.' in image_name:
            VV = image_path

    return xmlfile, HH, HV, VH, VV


def Get_QualifyValue_And_Calibration(xmlfile):
    tree = ET.parse(xmlfile)
    root = tree.getroot()

    HH_QualifyValue = root[17][13][0].text
    HV_QualifyValue = root[17][13][1].text
    VH_QualifyValue = root[17][13][2].text
    VV_QualifyValue = root[17][13][3].text
    QualifyValue = [HH_QualifyValue, HV_QualifyValue, VH_QualifyValue, VV_QualifyValue]

    QualifyValue_new = []
    for i in QualifyValue:
        if i != 'NULL':
            i = float(i)
            QualifyValue_new.append(i)
        else:
            i = np.NAN
            QualifyValue_new.append(i)

    HH_CalibrationConst = root[18][3][0].text
    HV_CalibrationConst = root[18][3][1].text
    VH_CalibrationConst = root[18][3][2].text
    VV_CalibrationConst = root[18][3][3].text
    CalibrationConst = [HH_CalibrationConst, HV_CalibrationConst, VH_CalibrationConst, VV_CalibrationConst]

    CalibrationConst_new = []
    for i in CalibrationConst:
        if i != 'NULL':
            i = float(i)
            CalibrationConst_new.append(i)
        else:
            i = np.NAN
            CalibrationConst_new.append(i)

    return QualifyValue_new, CalibrationConst_new


def Confirm_The_IMG_type(file, xmlfile):
    QualifyValue_new, CalibrationConst_new = Get_QualifyValue_And_Calibration(xmlfile)

    file_name = os.path.basename(file).upper()

    if '_HH_' in file_name or '_HH.' in file_name:
        QualifyValue_1A = QualifyValue_new[0]
        Calibration = CalibrationConst_new[0]
    elif '_HV_' in file_name or '_HV.' in file_name:
        QualifyValue_1A = QualifyValue_new[1]
        Calibration = CalibrationConst_new[1]
    elif '_VH_' in file_name or '_VH.' in file_name:
        QualifyValue_1A = QualifyValue_new[2]
        Calibration = CalibrationConst_new[2]
    elif '_VV_' in file_name or '_VV.' in file_name:
        QualifyValue_1A = QualifyValue_new[3]
        Calibration = CalibrationConst_new[3]
    else:
        raise ValueError(f"无法识别极化类型: {file}")

    return QualifyValue_1A, Calibration


def save_to_tiff(ds, img_name, outpath):
    base_name = os.path.basename(img_name)
    out_filename = base_name.replace('L1A', 'L1B')
    out_filename = os.path.join(outpath, out_filename)

    print("L1B数据保存到:", out_filename)
    os.makedirs(outpath, exist_ok=True)

    driver = gdal.GetDriverByName('GTiff')
    driver.Register()

    if ds.dtype == np.uint8:
        dtype = gdal.GDT_Byte
    elif ds.dtype == np.uint16:
        dtype = gdal.GDT_UInt16
    else:
        dtype = GDT_Float32

    outDataset = driver.Create(out_filename, ds.shape[1], ds.shape[0], 1, dtype, ['COMPRESS=DEFLATE'])
    outBand = outDataset.GetRasterBand(1)

    for i in range(ds.shape[0]):
        outBand.WriteArray(ds[i].reshape(1, -1), 0, i)

    outBand.FlushCache()
    outBand = None
    outDataset = None

    return out_filename


def Run_1Ato2(file, outpath, xmlfile, inputpath):
    try:
        print(f"开始处理文件: {file}")

        img = gdal.Open(file)
        if img is None:
            raise ValueError(f"无法打开文件: {file}")

        vh0 = img.ReadAsArray()
        vh1 = np.array(vh0[0, :, :], dtype='float32')
        vh2 = np.array(vh0[1, :, :], dtype='float32')

        I = (vh1 ** 2 + vh2 ** 2)
        A = np.sqrt(I)

        QualifyValue_1A, Calibration = Confirm_The_IMG_type(file, xmlfile)
        print(f'QualifyValue_1A={QualifyValue_1A}, Calibration={Calibration}')

        del vh0, vh1, vh2

        QualifyValue_1B = np.nanmax((A / 32767 * QualifyValue_1A))
        print(f'QualifyValue_1B={QualifyValue_1B}')

        DN = A / 32767 * QualifyValue_1A / QualifyValue_1B * 65535
        k1 = DN * (QualifyValue_1B / 65535)
        k2 = k1 ** 2
        del A, DN, k1

        dB_1B = 10 * np.log10(k2) - Calibration
        del k2

        tlstretch = truncated_linear_stretch(dB_1B, 2, max_out=65535, min_out=0)
        _1b_file_path = save_to_tiff(tlstretch, file, outpath)

        del dB_1B, tlstretch, I

        print(f"完成L1A到L1B处理: {file}")
        geometric_correction(_1b_file_path, outpath, inputpath)

    except Exception as e:
        print(f"处理文件 {file} 时出错: {e}")
        return None


def truncated_linear_stretch(image, truncated_value, max_out=65535, min_out=0):
    def gray_process(gray):
        truncated_down = np.percentile(gray, truncated_value)
        truncated_up = np.percentile(gray, 100 - truncated_value)

        if truncated_up == truncated_down:
            gray = np.zeros_like(gray)
        else:
            gray = (gray - truncated_down) / (truncated_up - truncated_down) * (max_out - min_out) + min_out

        gray[gray < min_out] = min_out
        gray[gray > max_out] = max_out

        if max_out <= 255:
            gray = np.uint8(gray)
        elif max_out <= 65535:
            gray = np.uint16(gray)

        return gray

    if len(image.shape) == 3:
        image_stretch = []
        for i in range(image.shape[0]):
            gray = gray_process(image[i])
            image_stretch.append(gray)
        image_stretch = np.array(image_stretch)
    else:
        image_stretch = gray_process(image)

    return image_stretch


def Repeat_Run_1Ato1B(image_name, outpath, xmlfile, inputpath):
    num_i = 1
    for file in image_name:
        if file:
            print(f'开始处理第{num_i}个文件: {os.path.basename(file)}')
            Run_1Ato2(file, outpath, xmlfile, inputpath)
        else:
            print(f'第{num_i}个文件为空,跳过')
        num_i += 1


def Read_Rpb(rpbfile):
    """修复版:正确处理GF-3 RPC文件格式"""

    # 参数名映射:从文件中的驼峰式到GDAL需要的大写下划线式
    PARAM_MAPPING = {
        'errBias': 'ERR_BIAS',
        'errRand': 'ERR_RAND',
        'lineOffset': 'LINE_OFF',
        'sampOffset': 'SAMP_OFF',
        'latOffset': 'LAT_OFF',
        'longOffset': 'LONG_OFF',
        'heightOffset': 'HEIGHT_OFF',
        'lineScale': 'LINE_SCALE',
        'sampScale': 'SAMP_SCALE',
        'latScale': 'LAT_SCALE',
        'longScale': 'LONG_SCALE',
        'heightScale': 'HEIGHT_SCALE',
        'lineNumCoef': 'LINE_NUM_COEFF',
        'lineDenCoef': 'LINE_DEN_COEFF',
        'sampNumCoef': 'SAMP_NUM_COEFF',
        'sampDenCoef': 'SAMP_DEN_COEFF'
    }

    rpc_dict = {}

    try:
        with open(rpbfile, 'r', encoding='utf-8') as f:
            content = f.read()

        # 方法1:简单但可靠的解析 - 直接查找每个参数
        for file_param, gdal_param in PARAM_MAPPING.items():
            # 查找格式:参数名 = 值;
            pattern = rf'{file_param}\s*=\s*([^;]+);'
            match = re.search(pattern, content, re.DOTALL)

            if match:
                value = match.group(1).strip()

                # 处理括号内的多行系数
                if value.startswith('('):
                    # 提取括号内的所有内容
                    value = re.search(r'\((.*?)\);', match.group(0), re.DOTALL)
                    if value:
                        value = value.group(1)
                        # 清理:移除换行、多余空格、逗号转换为空格
                        value = re.sub(r'\s+', ' ', value)  # 多个空格换行变一个空格
                        value = re.sub(r',\s*', ' ', value)  # 逗号+空格变空格
                        value = value.strip()

                rpc_dict[gdal_param] = value
                print(f"  ✓ {gdal_param}: {value[:50]}..." if len(str(value)) > 50 else f"  ✓ {gdal_param}: {value}")
            else:
                print(f"  ✗ {gdal_param}: 未找到")
                # 对于必需参数,设置默认值
                if gdal_param in ['ERR_BIAS', 'ERR_RAND']:
                    rpc_dict[gdal_param] = '-1.0'  # GDAL默认值
                elif 'OFF' in gdal_param:
                    rpc_dict[gdal_param] = '0.0'
                elif 'SCALE' in gdal_param:
                    rpc_dict[gdal_param] = '1.0'

        # 转换为GDAL需要的列表格式
        gdal_rpc_list = [f'{key}={value}' for key, value in rpc_dict.items()]

        print(f"✅ RPC解析成功:共{len(gdal_rpc_list)}个参数")
        return gdal_rpc_list

    except Exception as e:
        print(f"❌ RPC解析失败: {e}")
        # 返回空列表让几何校正跳过
        return []


def Get_Rpc_file(pathlog):
    rpc_fn = []

    for f_name in os.listdir(pathlog):
        if f_name.endswith('.rpc') or f_name.endswith('.rpb'):
            rpc_fn.append(os.path.join(pathlog, f_name))

    HH_rpc = None
    HV_rpc = None
    VH_rpc = None
    VV_rpc = None

    for rpc_path in rpc_fn:
        rpc_name = os.path.basename(rpc_path).upper()
        # 精确匹配极化类型
        if '_HH_' in rpc_name or '_HH.' in rpc_name:
            HH_rpc = rpc_path
        elif '_HV_' in rpc_name or '_HV.' in rpc_name:
            HV_rpc = rpc_path
        elif '_VH_' in rpc_name or '_VH.' in rpc_name:
            VH_rpc = rpc_path
        elif '_VV_' in rpc_name or '_VV.' in rpc_name:
            VV_rpc = rpc_path

    return [HH_rpc, HV_rpc, VH_rpc, VV_rpc]


def Confirm_The_rpc_type(file, inputpath):
    file_name = os.path.basename(file).upper()
    rpcfile_collection = Get_Rpc_file(inputpath)

    if '_HH_' in file_name or '_HH.' in file_name:
        rpcfile01 = rpcfile_collection[0]
    elif '_HV_' in file_name or '_HV.' in file_name:
        rpcfile01 = rpcfile_collection[1]
    elif '_VH_' in file_name or '_VH.' in file_name:
        rpcfile01 = rpcfile_collection[2]
    elif '_VV_' in file_name or '_VV.' in file_name:
        rpcfile01 = rpcfile_collection[3]
    else:
        raise ValueError(f"无法确定RPC文件类型: {file}")

    return rpcfile01


def geometric_correction(file, outputpath, inputpath):
    try:
        print(f'正在进行几何校正: {os.path.basename(file)}')

        rpcfile = Confirm_The_rpc_type(file, inputpath)
        if rpcfile is None:
            raise FileNotFoundError(f"未找到对应的RPC文件: {file}")

        print(f"RPC文件: {os.path.basename(rpcfile)}")

        rpc = Read_Rpb(rpcfile)
        dataset = gdal.Open(file)
        if dataset is None:
            raise ValueError(f"无法打开文件: {file}")

        for item in rpc:
            key, value = item.split('=', 1)
            dataset.SetMetadataItem(key, value, 'RPC')

        base_name = os.path.basename(file)
        out_filename = base_name.replace('L1B', 'L2')
        out_filename = os.path.join(outputpath, out_filename)

        print(f"几何校正输出: {out_filename}")

        # 添加分辨率设置(0.0001度约11米)
        gdal.Warp(out_filename, dataset,
                  dstSRS='EPSG:4326',
                  xRes=0.0001, yRes=0.0001,
                  rpc=True,
                  resampleAlg=gdal.GRA_Bilinear)

        print(f'完成几何校正: {out_filename}')
        dataset = None

    except Exception as e:
        print(f"几何校正失败: {e}")
        return None


if __name__ == '__main__':
    # 修改这里为您的路径
    inputpath = r'K:\GF3\untreatedGF3\GF3_KSC_FSII_046450_E71.0_N41.4_20250606_L1A_HHHV_L10007136652'
    outputpath = r'K:\GF3\output_gf3\\GF3_KSC_FSII_046450_E71.0_N41.4_20250606_L1A_HHHV_L10007136652'

    # 创建输出目录
    if not os.path.exists(outputpath):
        os.makedirs(outputpath)
        print(f"创建输出目录: {outputpath}")

    # 获取文件列表
    try:
        xmlfile, HH, HV, VH, VV = Get_File_Name(inputpath)
        print(f"元数据文件: {xmlfile}")
        print(f"HH极化文件: {HH}")
        print(f"HV极化文件: {HV}")
        print(f"VH极化文件: {VH}")
        print(f"VV极化文件: {VV}")

        # 过滤掉空值
        image_name = [f for f in [HH, HV, VH, VV] if f]

        if not image_name:
            print("警告: 未找到任何图像文件!")
        else:
            # 开始处理
            Repeat_Run_1Ato1B(image_name, outputpath, xmlfile, inputpath)
            print("所有处理完成!")

    except Exception as e:
        print(f"处理过程中出错: {e}")
相关推荐
生信大杂烩44 分钟前
空间转录组数据分析环境搭建:使用 Conda 和 VSCode 实现本地/远程无缝开发
python·数据分析
codists1 小时前
以 Core i9-13900HX 实例讲解CPU概念:物理CPU,内核,逻辑CPU
python
Salt_07281 小时前
DAY25 奇异值SVD分解
python·算法·机器学习
秋邱1 小时前
AR + 离线 AI 实战:YOLOv9+TensorFlow Lite 实现移动端垃圾分类识别
开发语言·前端·数据库·人工智能·python·html
程序员杰哥1 小时前
UI自动化测试框架:PO 模式+数据驱动
自动化测试·软件测试·python·selenium·测试工具·ui·测试用例
AI视觉网奇1 小时前
视频选帧截取
python·opencv·音视频
hmbbcsm1 小时前
练习python题目小记(七)
开发语言·python
qq_356196952 小时前
day27pipeline管道@浙大疏锦行
python
噔噔噔噔@2 小时前
第一章、基础理论——第一节、软件测试概述
python·单元测试·压力测试