Landsat8处理小工具(python)

再更新

决定将重构的代码更新在这篇博客中。现在实现的功能:读、写、多波段的辐射定标(可定表观辐射亮度或表观反射率)、图像分片功能(全部带坐标)。
读取可选多光谱波段、全色波段、热红外波段,读入numpy数组。
辐射定标后读入numpy数组。

更新

决定不再更新这段代码,而是重构代码。因为强行使用装饰器等,工具使用起来十分蹩脚。至于新的重构代码,功能会更加齐全,会更新在新的博客中。

之前内容

暂时有了读、写、分块(写出时暂无坐标)、多光谱辐射定标等功能。
下面会不停更新此博客,进而更新代码。

至于为什么用装饰器等,主要是为了练习使用而已。

代码

# -*-coding:utf-8-*-
#
# @author:rsstudent
#

import numpy as np
from osgeo import gdal
from osgeo import gdal_array
import cv2 as cv
import math
from numba import jit
from functools import wraps
import os

class Landsat8Tools(object):

    def __init__(self):
        self.LANDSAT8_MULTI_BAND_NUM = 7
        self.LANDSAT8_THERMAL_BAND_NUM = 2
        self.LANDSAT8_PAN_BAND_NUM = 1
        self.LANDSAT8_PAN_BAND = 8
        self.LANDSAT8_THERMAL_START_BAND = 10
        self.multi_nan_position = []
        self.pan_nan_position = []
        self.thermal_nan_position = []
        self.process_image_nan_position = []


    def __get_base_name(self, full_name):
        base_names = full_name.split("_")[:-1]
        base_name = ""
        for string in base_names:
            base_name += (string + "_")
        return base_name


    def read_multi_band_to_image(self, mtl_file_path):
        
        multi_band_file_names = []

        base_name = self.__get_base_name(mtl_file_path)
        
        for band in range(self.LANDSAT8_MULTI_BAND_NUM):
            band_name = base_name + "B" + str(band + 1) + ".tif"
            multi_band_file_names.append(band_name)

        if len(multi_band_file_names) == 0:
            raise Exception("The filename is incorrect!")

        dataset = gdal.Open(multi_band_file_names[0], gdal.GA_ReadOnly)

        if dataset == None:
            raise Exception("Fail to open the image file.")
        
        height = dataset.RasterYSize
        width = dataset.RasterXSize

        image = np.zeros((height, width, self.LANDSAT8_MULTI_BAND_NUM), dtype = np.float16)
        projection = dataset.GetProjection()
        geotransform = dataset.GetGeoTransform()
        del dataset

        print("read multi band start, please wait...")
        for band in range(self.LANDSAT8_MULTI_BAND_NUM):
            ds = gdal.Open(multi_band_file_names[band], gdal.GA_ReadOnly)
            band_image = ds.GetRasterBand(1)
            image[:, :, band] = band_image.ReadAsArray()
            del ds
        print("read  multi band finish.")
        self.multi_nan_position = np.where(image == 0)
        image[self.multi_nan_position] = np.nan

        return image, projection, geotransform

    def read_pan_band_to_image(self, mtl_file_path):
        base_name = self.__get_base_name(mtl_file_path)
        pan_file_name = base_name + "B8" + ".tif"
        
        dataset = gdal.Open(pan_file_name, gdal.GA_ReadOnly)
        if dataset == None:
            raise Exception("Image name error.")
        else:
            datatype = np.float16
            height = dataset.RasterYSize
            width = dataset.RasterXSize
            projection = dataset.GetProjection()
            geotransform = dataset.GetGeoTransform()

            pan_image = np.zeros((height, width, 1), dtype = datatype)
            print("read pan start, please wait...")
            band_data = dataset.GetRasterBand(1)
            pan_image[:, :, 0] = band_data.ReadAsArray()
            del dataset

        self.pan_nan_position = np.where(pan_image == 0)
        pan_image[self.pan_nan_position] = np.nan
        print("read pan finish.")

        return pan_image, projection, geotransform

    def read_thermal_band_to_image(self, mtl_file_path):
        nan_position = []
        base_name = self.__get_base_name(mtl_file_path)
        thermal_band10_file_name = base_name + "B10" + ".tif"
        thermal_band11_file_name = base_name + "B11" + ".tif"

        names = []
        names.append(thermal_band10_file_name)
        names.append(thermal_band11_file_name)

        dataset = gdal.Open(thermal_band10_file_name, gdal.GA_ReadOnly)
        if dataset == None:
            raise Exception("Image name error.")
        else:
            datatype = np.float16
            height = dataset.RasterYSize
            width = dataset.RasterXSize
            projection = dataset.GetProjection()
            geotransform = dataset.GetGeoTransform()
            thermal_image = np.zeros((height, width, 2), dtype = datatype)
            del dataset
        print("read thermal band start, please wait...")
        for band in range(self.LANDSAT8_THERMAL_BAND_NUM):
            ds = gdal.Open(names[band], gdal.GA_ReadOnly)
            band_data = ds.GetRasterBand(1)
            thermal_image[:, :, band] = band_data.ReadAsArray()
            del ds
        
        self.thermal_nan_position = np.where(thermal_image == 0)
        thermal_image[self.thermal_nan_position] == np.nan
        print("read thermal band finish.", end = "")

        return thermal_image, projection, geotransform

    def read_single_band_to_image(self, mtl_file_path, band_num):

        base_name =self.__get_base_name(mtl_file_path)
        nan_position = []
        fullbandname = base_name + "B" + str(band_num) + ".tif"
        dataset = gdal.Open(fullbandname, gdal.GA_ReadOnly)
        if dataset == None:
            raise Exception("Image name error.")
        else:
            datatype = np.float16
            height = dataset.RasterYSize
            width = dataset.RasterXSize
            projection = dataset.GetProjection()
            geotransform = dataset.GetGeoTransform()

            band_image = np.zeros((height, width, 1), dtype = datatype)

            print("read single band start")
            band_data = dataset.GetRasterBand(1)
            band_image[:, :, 0] = band_data.ReadAsArray()
            del dataset
            print("read single band finish.")
        
        self.process_image_nan_position = np.where(band_image == 0)
        band_image[self.process_image_nan_position] == np.nan

        return band_image, projection, geotransform

    def save(self, save_path, image, projection, geotransform, format = 'GTiff'):
        datatype = gdal.GDT_Float32
        DIMENSION_OF_IMAGE = 3
        if len(image.shape) != DIMENSION_OF_IMAGE:
            raise Exception("The dimension of the image is incorrect.")
        else:
            height = image.shape[0]
            width = image.shape[1]
            channels = image.shape[2]

        driver = gdal.GetDriverByName(format)
        ds_to_save = driver.Create(save_path, width, height, channels, datatype)
        ds_to_save.SetGeoTransform(geotransform)
        ds_to_save.SetProjection(projection)

        print("save tool start, please wait...")
        for band in range(channels):
            ds_to_save.GetRasterBand(band + 1).WriteArray(image[:, :, band])
            ds_to_save.FlushCache()

        print("save finish.")
        del image
        del ds_to_save

    def radiometric_calibration(self, mtl_file_path, save_folder, cali_type = "radiance"):
        
        f = open(mtl_file_path, 'r')
        metadata = f.readlines()
        f.close()
        radiance_multi_paras = []
        radiance_add_paras = []

        reflectance_multi_paras = []
        reflectance_add_paras = []
        
        radiance_paras_start_line = 0
        reflectance_paras_start_line = 0

        for lines in metadata:
            test_line = lines.split("=")
            if test_line[0] == '    REFLECTANCE_MULT_BAND_1 ':
                break
            else:
                reflectance_paras_start_line += 1

        for lines in range(reflectance_paras_start_line, reflectance_paras_start_line + 9):
            parameter = float(metadata[lines].split('=')[1])
            reflectance_multi_paras.append(parameter)

        for lines in range(reflectance_paras_start_line + 9, reflectance_paras_start_line + 18):
            parameter = float(metadata[lines].split('=')[1])
            reflectance_add_paras.append(parameter)        

        for lines in metadata:
            test_line = lines.split("=")
            if test_line[0] == '    RADIANCE_MULT_BAND_1 ':
                break
            else:
                radiance_paras_start_line += 1

        for lines in range(radiance_paras_start_line, radiance_paras_start_line + 11):
            parameter = float(metadata[lines].split('=')[1])
            radiance_multi_paras.append(parameter)

        for lines in range(radiance_paras_start_line + 11, radiance_paras_start_line + 22):
            parameter = float(metadata[lines].split('=')[1])
            radiance_add_paras.append(parameter)

        if cali_type != "radiance" and cali_type != "reflectance":
            raise Exception("cali_type is incorrect.")

        if cali_type == "radiance":
            
            multi_image, multi_projection, multi_geotransform = self.read_multi_band_to_image(mtl_file_path)

            print("radiance radiomereic calibration start.")

            for band in range(self.LANDSAT8_MULTI_BAND_NUM):
                gain = radiance_multi_paras[band]
                offset = radiance_multi_paras[band]
                multi_image[:, :, band] = multi_image[:, :, band]*gain + offset
            
            multi_image[self.multi_nan_position] = np.nan
            multi_image_name = "radiance_multi.tif"
            save_path = os.path.join(save_folder, multi_image_name)
            self.save(save_path, multi_image, multi_projection, multi_geotransform)
            del multi_image

            pan_image, pan_projection, pan_geotransform = self.read_pan_band_to_image(mtl_file_path)
            pan_gain = radiance_multi_paras[7]
            pan_offset = radiance_add_paras[7]

            pan_image = pan_image * gain + offset
            pan_image[self.pan_nan_position] = np.nan
            pan_image_name = "radiance_pan.tif"
            save_path = os.path.join(save_folder, pan_image_name)
            self.save(save_path, pan_image, pan_projection, pan_geotransform)
            del pan_image
            
            thermal_image, thermal_projection, thermal_geotransform = self.read_thermal_band_to_image(mtl_file_path)
            thermal_multi_paras = []
            thermal_add_paras = []

            thermal_multi_paras.append(radiance_multi_paras[9])
            thermal_multi_paras.append(radiance_multi_paras[10])
            thermal_add_paras.append(radiance_add_paras[9])
            thermal_add_paras.append(radiance_add_paras[10])
            
            for band in range(self.LANDSAT8_THERMAL_BAND_NUM):
                thermal_image[:, :, band] = thermal_image[:, :, band] * thermal_multi_paras[band] + thermal_add_paras[band]
    
            thermal_image[self.thermal_nan_position] = np.nan
            thermal_image_name = "radiance_thermal.tif"
            save_path = os.path.join(save_folder, thermal_image_name)
            self.save(save_path, thermal_image, thermal_projection, thermal_geotransform)
            
            print("ridiometric calibraion finish.")
            del thermal_image
        else:
            
            multi_image, multi_projection, multi_geotransform = self.read_multi_band_to_image(mtl_file_path)

            print("reflectance radiomereic calibration start.")
            for band in range(self.LANDSAT8_MULTI_BAND_NUM):
                gain = reflectance_multi_paras[band]
                offset = reflectance_multi_paras[band]
                multi_image[:, :, band] = multi_image[:, :, band]*gain + offset

            multi_image[self.multi_nan_position] = np.nan
            multi_image_name = "reflectance_multi.tif"
            save_path = os.path.join(save_folder, multi_image_name)
            self.save(save_path, multi_image, multi_projection, multi_geotransform)
            del multi_image

            pan_image, pan_projection, pan_geotransform = self.read_pan_band_to_image(mtl_file_path)
            pan_gain = reflectance_multi_paras[7]
            pan_offset = reflectance_add_paras[7]

            pan_image = pan_image * gain + offset
            pan_image[self.pan_nan_position] = np.nan

            pan_image_name = "reflectance_pan.tif"
            save_path = os.path.join(save_folder, pan_image_name)
            self.save(save_path, pan_image, pan_projection, pan_geotransform)
            del pan_image
            
            thermal_image, thermal_projection, thermal_geotransform = self.read_thermal_band_to_image(mtl_file_path)
            thermal_multi_paras = []
            thermal_add_paras = []

            thermal_multi_paras.append(radiance_multi_paras[9])
            thermal_multi_paras.append(radiance_multi_paras[10])
            thermal_add_paras.append(radiance_add_paras[9])
            thermal_add_paras.append(radiance_add_paras[10])
            
            
            for band in range(self.LANDSAT8_THERMAL_BAND_NUM):
                thermal_image[:, :, band] = thermal_image[:, :, band] * thermal_multi_paras[band] + thermal_add_paras[band]

            thermal_image[self.thermal_nan_position] = np.nan
            thermal_image_name = "radiance_thermal.tif"
            save_path = os.path.join(save_folder, thermal_image_name)
            self.save(save_path, thermal_image, thermal_projection, thermal_geotransform)
            print("radiometric calibraion finish.")
            del thermal_image

    def cut_to_tile_with_geoinfo(self, save_folder, image_size, image, projection, geotransform, format = "GTiff"):
        print("cut to tile with geoinfo tool start.")
        DIMENSION_OF_IMAGE = 3

        if len(image_size) !=  DIMENSION_OF_IMAGE:
            raise Exception("your image dimension is incorrect.Need 3-d array.")

        image_height = image.shape[0]
        image_width = image.shape[1]
        image_channels = image.shape[2]

        tile_height = image_size[0]
        tile_width = image_size[1]
        channels = image_size[2]

        if image_channels != channels:
            raise Exception("Your image channels isn't match the required channels.")

        num_rows = math.floor(image_height/tile_height)
        num_cols = math.floor(image_width/tile_width)
        useful_height = num_rows * tile_height
        useful_width = num_cols * tile_width

        image = np.array(image[:useful_height, :useful_width, :])

        x_origin_point = geotransform[0]
        x_pixel_size = geotransform[1]
        x_ro = geotransform[2]
        y_origin_point = geotransform[3]
        y_ro = geotransform[4]
        y_pixel_size = geotransform[5]
        i = 0
        x_offset = 0
        y_offset = 0
        
        for tile_row in range(num_rows):
            for tile_col in range(num_cols):
                tile = image[tile_row*tile_width: (tile_row+1)*tile_width, tile_col*tile_height:(tile_col+1)*tile_height, :]
                filename = str(i) + '.tif'
                path = os.path.join(save_folder, filename)
                tile = np.float32(tile)
                tile_x_origin_point = x_origin_point + x_pixel_size * tile_col * tile_width
                tile_y_origin_point = y_origin_point + y_pixel_size * tile_row * tile_height
                tile_geotransform = (tile_x_origin_point, x_pixel_size, x_ro, tile_y_origin_point, y_ro, y_pixel_size)
                self.save(path, tile, projection, tile_geotransform, format)
                i += 1
                del tile

        print("cut to tile with geoinfo tool finish.")
        del image

if __name__ == "__main__":
    tool = Landsat8Tools()
    mtl_file_path = "F:\SRGAN_program\dataset\LC81290352019095LGN00\LC08_L1TP_129035_20190405_20190422_01_T1_MTL.txt"
    save_folder = "F:\\SRGAN_program\\dataset\\LC81290352019095LGN00\\tiles"
    save_folder1 = "F:\\SRGAN_program\\dataset\\LC81290352019095LGN00\\test\\ppan"
    pan, projection, geotransform = tool.read_pan_band_to_image(mtl_file_path)
    tool.cut_to_tile_with_geoinfo(save_folder, (256, 256, 1), pan, projection, geotransform)
    #tool.save(save_folder1, pan, projection, geotransform)
        

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Landsat 8是一颗遥感卫星,用于收集地球表面的高分辨率图像。Python是一种流行的程序设计语言,提供了许多功能强大的库和工具处理遥感数据。 在使用Python进行Landsat 8温度数据处理时,主要有以下几个步骤: 1. 数据获取:通过合适的数据源,比如美国地质调查局(USGS)的数据存档,可以获取到Landsat 8的温度数据集。 2. 数据解析:使用Python中的GDAL库或其他相关库,可以读取并解析Landsat 8的数据文件。这些数据文件通常是以GeoTIFF(地理标记图像文件格式)的形式存储的。 3. 数据预处理:在对温度数据进行分析之前,通常需要进行预处理。这可能包括去除云层遮挡、空间插值或差值方法进行修复等操作。 4. 温度计算:使用提供的辐射定标系数,可以将Landsat 8的原始辐射数据转换为表面温度数据。这些辐射定标系数可以在Landsat 8的技术文档中找到。 5. 数据分析:使用Python中的各种数据分析库,如NumPy、Pandas和Matplotlib等,可以对Landsat 8温度数据进行各种统计和可视化分析。比如制作温度分布图、温度时间序列图等。 通过这些步骤,我们可以使用PythonLandsat 8的温度数据进行处理和分析,从而获取更多关于地表温度的信息,进而应用于环境监测、气候研究和自然资源管理等领域。Python的开源特性以及强大的科学计算能力,使得分析Landsat 8温度数据变得更加高效和便捷。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值