【PythonRS】植被显示增强(多光谱、正射、照片等)

news2024/10/3 0:33:24

        很多时候我们需要某个区域的正射图,虽然正射图一般都运用了匀色的算法,整体色彩比较均衡。但如果研究区内有大量的植被,这个时候植被突出显示就很有必要了。所以今天给大家分享一下使用Python对多光谱、正射影像进行植被显示增强的算法。

一、加载需要的库

        这里的主要库是numpy用来读取图片的数组,gdal库用来读取多光谱数据。

import numpy as np
from osgeo import gdal
import tkinter.filedialog
# 创建窗口打开图片模块

二、多光谱数据增强

1.获取影像的基本信息

        这一步没啥用,可以不放进代码。主要让你先了解一下自己的数据。

def Get_data(filepath):
    """
    :param filepath: 输入数据路径
    :return: 输出影像的基本信息
    """
    ds = gdal.Open(filepath)  # 打开数据集dataset
    ds_width = ds.RasterXSize  # 获取数据宽度
    ds_height = ds.RasterYSize  # 获取数据高度
    ds_bands = ds.RasterCount  # 获取波段数
    ds_geo = ds.GetGeoTransform()  # 获取仿射地理变换参数
    ds_prj = ds.GetProjection()  # 获取投影信息
    print("影像的宽度为:" + str(ds_width))
    print("影像的高度为:" + str(ds_height))
    print("影像的波段数为:" + str(ds_bands))
    print("仿射地理变换参数为:" + str(ds_geo))
    print("投影坐标系为:" + str(ds_prj))
    # data = ds.ReadAsArray(0, 0, ds_width, ds_height)  # 以数组的形式读取整个数据集

2.算法核心

        由于多光谱是包含近红外波段的,同时呢,我们知道植被对于近红外波段有着很强的反射,其栅格值也会很大。所以这里我们使用近红外波段近似代替绿波段,这样就可以达到植被显示增强的目的了。但如果只是单纯的替代,那么其他对绿波段有反射的地物的颜色就会失真,你就会发现增强后,整个图变得非常奇怪。所以这里我们设定一个阈值,将绿波段和近红外波段综合起来再去代替绿波段。

Green = Green*0.8+NIR*0.2

3.代码实现

        这里我就不过多的解释了,因为里面的一些函数我之前发布的博文里都已经解释过了,同时代码我也做了详细的注释,所以大家直接看吧

def Enhance_Veg(filepath, out_path, green, nir):
    """
    :param filepath: 输入需要增强的图片路径
    :param out_path: 输入保存文件的路径
    :param green: 输入绿波段
    :param nir: 输入近红外波段
    :return:
    """
    ds = gdal.Open(filepath)  # 打开数据集dataset
    ds_width = ds.RasterXSize  # 获取数据宽度
    ds_height = ds.RasterYSize  # 获取数据高度
    ds_geo = ds.GetGeoTransform()  # 获取仿射地理变换参数
    ds_prj = ds.GetProjection()  # 获取投影信息
    ds_bands = ds.RasterCount  # 获取波段数
    driver = gdal.GetDriverByName('GTiff')  # 载入数据驱动,用于存储内存中的数组
    ds_result = driver.Create(out_path, ds_width, ds_height, bands=ds_bands+1, eType=gdal.GDT_Float64)
    # 创建一个数组,宽高为原始尺寸
    ds_result.SetGeoTransform(ds_geo)  # 导入仿射地理变换参数
    ds_result.SetProjection(ds_prj)  # 导入投影信息
    array_green = ds.GetRasterBand(green).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_nir = ds.GetRasterBand(nir).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_new_green = array_green * 0.8 + array_nir * 0.2
    for i in range(1, ds_bands):
        array_band = ds.GetRasterBand(i).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
        ds_result.GetRasterBand(i).SetNoDataValue(0)  # 将无效值设为0
        ds_result.GetRasterBand(i).WriteArray(array_band)  # 将每个波段写入新的文件中
    ds_result.GetRasterBand(ds_bands+1).WriteArray(array_new_green)  # 将计算好的新绿波段写入
    del ds_result
    # 删除内存中的结果,否则结果不会写入图像中

三、RGB图像植被增强(正射影像)

1.算法核心

        由于RGB影像是没有近红外波段的,那么我们该怎么才能即增强植被的显示效果,又不改变其他地物的显示效果呢?这里我通过计算两种无需近红外波段就能计算的植被指数作为阈值计算的对象。很多植被指数我都试验过了,就这两种效果比较好:

1)绿叶指数 (GLI)

        GLI 指数在识别所有这些绿色和深色时非常敏感。负值将显示裸露的土壤、水体和人造基础设施。相反,正值就是类似于 NDVI 的颜色渐变来识别植被覆盖。如果你所在的区域有阴影、绿色潮湿的区域或裸露、潮湿和深色的土壤,应注意不要将植物覆盖分类错误。

GLI = ((绿 - 红) + (绿 - 蓝)) / ((2 * 绿) + 红 + 蓝)

2)红绿蓝植被指数 (RGBVI)

        利用可见光的三个波段。需要对值进行无监督的分类,以将植物与其他土地覆盖区分开来。

RGBVI = ((绿 * 绿) - (红 * 蓝)) / ((绿 * 绿) + (红 + 蓝))

        我们得到两种植被指数后,就需要建立一个合适的算法,去近似代替绿波段。这里我自己提出了两种算法,都是我实验之后效果比较好的:

Green = Green+Green*GLI

Green = Green*0.8+RGBVI*255*0.2

2.代码实现

        这个函数在运行时,会询问你需要使用哪种算法,再程序询问时,输入1或者2回车即可。

def Enhance_Veg_RGB(filepath, out_path, red, green, blue):
    """
    :param filepath: 输入需要增强的图片路径
    :param out_path: 输入保存文件的路径
    :param red: 输入红波段
    :param green: 输入绿波段
    :param blue: 输入蓝波段
    :return:
    """
    np.seterr(divide='ignore', invalid='ignore')
    ds = gdal.Open(filepath)  # 打开数据集dataset
    ds_width = ds.RasterXSize  # 获取数据宽度
    ds_height = ds.RasterYSize  # 获取数据高度
    ds_geo = ds.GetGeoTransform()  # 获取仿射地理变换参数
    ds_prj = ds.GetProjection()  # 获取投影信息
    ds_bands = ds.RasterCount  # 获取波段数
    driver = gdal.GetDriverByName('GTiff')  # 载入数据驱动,用于存储内存中的数组
    ds_result = driver.Create(out_path, ds_width, ds_height, bands=ds_bands+1, eType=gdal.GDT_Float64)
    # 创建一个数组,宽高为原始尺寸
    ds_result.SetGeoTransform(ds_geo)  # 导入仿射地理变换参数
    ds_result.SetProjection(ds_prj)  # 导入投影信息
    array_red = ds.GetRasterBand(red).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_green = ds.GetRasterBand(green).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_blue = ds.GetRasterBand(blue).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    GLI = ((array_green-array_red) + (array_green-array_blue))/((array_green*2)+array_red+array_blue)
    RGBVI = ((array_green*array_green)-(array_red*array_blue))/((array_green*array_green)+(array_red+array_blue))
    array_new_green = 0
    chance = int(input("请选择增强算法:1:GLI, 2:RGBVI\n"))
    if chance == 1:
        array_new_green = array_green + array_green*GLI
    elif chance == 2:
        array_new_green = array_green*0.8+RGBVI*0.2*255
    else:
        print('选择错误!')
    for i in range(1, ds_bands+1):
        array_band = ds.GetRasterBand(i).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
        ds_result.GetRasterBand(i).SetNoDataValue(0)  # 将无效值设为0
        ds_result.GetRasterBand(i).WriteArray(array_band)  # 将每个波段写入新的文件中
    ds_result.GetRasterBand(ds_bands+1).SetNoDataValue(0)
    ds_result.GetRasterBand(ds_bands+1).WriteArray(array_new_green)  # 将计算好的新绿波段写入
    del ds_result
    # 删除内存中的结果,否则结果不会写入图像中

四、完整代码

        我这里使用了tkinter.filedialog调用了GUI窗口,以便于更方便地选取需要增强的图片。本来还想封装成程序的,但我太懒了。本来还想再出个ENVI实现的教程的,但我太懒了。所以现在还需要手动输入波段索引,同时还需要自己确定使用多光谱还是RGB增强函数。

        我这里还写了一个压缩函数,可以不要但不能没有。代码中已经注释掉了,不会用就不用。

# -*- coding: utf-8 -*-
"""
@Time : 2023/8/10 17:45
@Auth : RS迷途小书童
@File :Vegetation Enhancement.py
@IDE :PyCharm
@Purpose :影像中植被增强显示
"""
import numpy as np
from osgeo import gdal
import tkinter.filedialog
# 创建窗口打开图片模块


def Get_data(filepath):
    """
    :param filepath: 输入数据路径
    :return: 输出影像的基本信息
    """
    ds = gdal.Open(filepath)  # 打开数据集dataset
    ds_width = ds.RasterXSize  # 获取数据宽度
    ds_height = ds.RasterYSize  # 获取数据高度
    ds_bands = ds.RasterCount  # 获取波段数
    ds_geo = ds.GetGeoTransform()  # 获取仿射地理变换参数
    ds_prj = ds.GetProjection()  # 获取投影信息
    print("影像的宽度为:" + str(ds_width))
    print("影像的高度为:" + str(ds_height))
    print("影像的波段数为:" + str(ds_bands))
    print("仿射地理变换参数为:" + str(ds_geo))
    print("投影坐标系为:" + str(ds_prj))
    # data = ds.ReadAsArray(0, 0, ds_width, ds_height)  # 以数组的形式读取整个数据集


def Enhance_Veg(filepath, out_path, green, nir):
    """
    :param filepath: 输入需要增强的图片路径
    :param out_path: 输入保存文件的路径
    :param green: 输入绿波段
    :param nir: 输入近红外波段
    :return:
    """
    ds = gdal.Open(filepath)  # 打开数据集dataset
    ds_width = ds.RasterXSize  # 获取数据宽度
    ds_height = ds.RasterYSize  # 获取数据高度
    ds_geo = ds.GetGeoTransform()  # 获取仿射地理变换参数
    ds_prj = ds.GetProjection()  # 获取投影信息
    ds_bands = ds.RasterCount  # 获取波段数
    driver = gdal.GetDriverByName('GTiff')  # 载入数据驱动,用于存储内存中的数组
    ds_result = driver.Create(out_path, ds_width, ds_height, bands=ds_bands+1, eType=gdal.GDT_Float64)
    # 创建一个数组,宽高为原始尺寸
    ds_result.SetGeoTransform(ds_geo)  # 导入仿射地理变换参数
    ds_result.SetProjection(ds_prj)  # 导入投影信息
    array_green = ds.GetRasterBand(green).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_nir = ds.GetRasterBand(nir).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_new_green = array_green * 0.8 + array_nir * 0.2
    for i in range(1, ds_bands):
        array_band = ds.GetRasterBand(i).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
        ds_result.GetRasterBand(i).SetNoDataValue(0)  # 将无效值设为0
        ds_result.GetRasterBand(i).WriteArray(array_band)  # 将每个波段写入新的文件中
    ds_result.GetRasterBand(ds_bands+1).WriteArray(array_new_green)  # 将计算好的新绿波段写入
    del ds_result
    # 删除内存中的结果,否则结果不会写入图像中


def Image_Compress(path_image, path_out_image):
    """
    :param path_image: 输入需要压缩的影像路径
    :param path_out_image: 输出压缩后的影像路径
    :return: None
    """
    ds = gdal.Open(path_image)
    # 打开影像数据
    driver = gdal.GetDriverByName('GTiff')
    # 创建输出的数据驱动
    driver.CreateCopy(path_out_image, ds, strict=1, options=["TILED=YES", "COMPRESS=PACKBITS", "BIGTIFF=YES"])
    # 设置压缩参数
    """
    PACKBITS:连续字节压缩,快速无损压缩
    LZW:所有信息全部保留(可逆),以某一数值代替字符串,快速无损压缩
    """
    del ds


def Enhance_Veg_RGB(filepath, out_path, red, green, blue):
    """
    :param filepath: 输入需要增强的图片路径
    :param out_path: 输入保存文件的路径
    :param red: 输入红波段
    :param green: 输入绿波段
    :param blue: 输入蓝波段
    :return:
    """
    np.seterr(divide='ignore', invalid='ignore')
    ds = gdal.Open(filepath)  # 打开数据集dataset
    ds_width = ds.RasterXSize  # 获取数据宽度
    ds_height = ds.RasterYSize  # 获取数据高度
    ds_geo = ds.GetGeoTransform()  # 获取仿射地理变换参数
    ds_prj = ds.GetProjection()  # 获取投影信息
    ds_bands = ds.RasterCount  # 获取波段数
    driver = gdal.GetDriverByName('GTiff')  # 载入数据驱动,用于存储内存中的数组
    ds_result = driver.Create(out_path, ds_width, ds_height, bands=ds_bands+1, eType=gdal.GDT_Float64)
    # 创建一个数组,宽高为原始尺寸
    ds_result.SetGeoTransform(ds_geo)  # 导入仿射地理变换参数
    ds_result.SetProjection(ds_prj)  # 导入投影信息
    array_red = ds.GetRasterBand(red).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_green = ds.GetRasterBand(green).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    array_blue = ds.GetRasterBand(blue).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
    GLI = ((array_green-array_red) + (array_green-array_blue))/((array_green*2)+array_red+array_blue)
    RGBVI = ((array_green*array_green)-(array_red*array_blue))/((array_green*array_green)+(array_red+array_blue))
    array_new_green = 0
    chance = int(input("请选择增强算法:1:GLI, 2:RGBVI\n"))
    if chance == 1:
        array_new_green = array_green + array_green*GLI
    elif chance == 2:
        array_new_green = array_green*0.8+RGBVI*0.2*255
    else:
        print('选择错误!')
    for i in range(1, ds_bands+1):
        array_band = ds.GetRasterBand(i).ReadAsArray(0, 0, ds_width, ds_height).astype(np.float64)
        ds_result.GetRasterBand(i).SetNoDataValue(0)  # 将无效值设为0
        ds_result.GetRasterBand(i).WriteArray(array_band)  # 将每个波段写入新的文件中
    ds_result.GetRasterBand(ds_bands+1).SetNoDataValue(0)
    ds_result.GetRasterBand(ds_bands+1).WriteArray(array_new_green)  # 将计算好的新绿波段写入
    del ds_result
    # 删除内存中的结果,否则结果不会写入图像中


if __name__ == "__main__":
    fn_input = open(
        tkinter.filedialog.askopenfilename(title='选择图片', filetypes=[('所有文件', '.*'), ('JPG', '.jpg'), ('JPG', '.jpeg'),
            ('TIFF', '.tif'), ('DAT', '.dat'), ('PNG', '.png')]), 'rb')
    # 输入的栅格数据路径
    fn_output = tkinter.filedialog.asksaveasfilename(defaultextension='.tif')
    # 导出的文件路径
    Get_data(fn_input.name)
    # Enhance_Veg(fn_input.name, fn_output, green=2, nir=4)  # 执行多光谱植被增强函数
    Enhance_Veg_RGB(fn_input.name, fn_output, red=1, green=2, blue=3)  # 执行RGB植被增强函数
    # Image_Compress(fn_output, fn_output)

五、效果图

        两图均是2%线性拉伸显示的效果。植被增强的效果很明显。

图1   原始图像

 图2   植被增强后

        需要注意的是,我为了保护原始文件,将新计算的绿波段加在了最后一个波段,所以要想查看增强效果,就用最后一个波段当成绿波段去真彩色显示!!!

        总的来说,本次博文分享的算法效果还不错。但代码并没有集成好,勉勉强强能用就行,感兴趣的话可以自己将它封装成程序。

        由于我代码中已给详细的解释,所以就不单独加以文字说明了。本文章主要是分享个人在学习Python过程中写过的一些代码。有些部分借鉴了前人以及官网的教程,如有侵权请联系作者删除,大家有问题可以随时留言交流,博主会及时回复。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/864881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频怎么变成gif表情包?在线视频转动图怎么做?

当我们在电脑上观看视频时,有时会遇到一些有趣的片段,如果想把这些视频转gif图片,就需要用到视频转gif工具(https://www.gif.cn),今天分享一个使用视频在线转gif功能来完成gif制作的方法,下面是…

代谢组学市场分析,制药及生物制药行业正在推动全球代谢组学产业的发展

代谢组学是对某一生物或细胞所有小分子量代谢产物进行定性和定量分析的一门新兴学科,其揭示的小分子代谢产物变化是机体内基因、蛋白质/酶等功能变化的一系列事件的最终结果,直接反映了生物体系的最终状态,可以反映机体特定病理生理状态下整体…

UML-时序图

目录 时序图 时序图构成: 对象: 消息: 生命线(激活): 活动条: 时序图举例: 时序图 时序图也叫顺序图、序列图. 时序图描述按照时间的先后顺序对象之间的动作过程,是由生命线和消息组成 时序图构成: 对象: 对象是类的实例,对象是通过类来创建的&…

【STM32RT-Thread零基础入门】 3. PIN设备(GPIO)的使用

硬件:STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 文章目录 前言一、PIN设备介绍1. 引脚编号获取2. 设置引脚的输入/输出模式3. 设置引脚的电平值4. 读取引脚的电平值5. 绑定引脚中断回调函数6. 脱离引脚中断…

微信开发之获取收藏夹列表的技术实现

简要描述: 获取收藏夹内容 请求URL: http://域名地址/weChatFavorites/favSync 请求方式: POST 请求头Headers: Content-Type:application/jsonAuthorization:login接口返回 参数: 参数…

深度使用苹果M1 Mac电脑一个月后的发现与问题解决

自从苹果推出M1芯片的Mac电脑后,其强大的性能和高效的能耗管理引起了广泛关注。许多人纷纷购买了这款新一代的Mac电脑,并深度使用了一个月。然而,在长时间使用的过程中,一些问题也逐渐浮现出来。本文将分享在深度使用苹果M1 Mac电…

【C++】dynamic_cast基本用法(详细讲解)

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

研究论文关于火灾的烟雾探测

普拉萨梅什加德卡尔 探索所有模型以选择最佳模型。 一、介绍: 烟雾探测器检测烟雾并触发警报以提醒他人。通常,它们存在于办公室、家庭、工厂等。通常,烟雾探测器分为两类: Photoelectric Smoke Detector- 设备检测光强度&#x…

8086汇编语言工作环境 百度网盘下载

链接:https://pan.baidu.com/s/1-1K7gX859xejaUK70OTgtw?pwdbfa5 提取码:bfa5 为了方便下载,找了很多资料,也是从其他人那边分享过来的,也方便其他人 文件内容:

如何快速解决集成环信IM遇到的问题?

1、环信FAQ频道发布了 环信FAQ帮助中心提供了各客户端、RESTful API、环信控制台以及商务相关的集成环信常见问题及解决方法,帮您快速解决集成问题 2、当我有问题时,从哪里进FAQ? 干脆收藏这个网址:https://faq.easemob.com/ 环…

逆向破解学习-割绳子

试玩 支付失败,请检查网络设置 Hook成功 Hook代码 import android.app.Application; import android.content.Context;import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_…

书写自动智慧:探索Python文本分类器的开发与应用:支持二分类、多分类、多标签分类、多层级分类和Kmeans聚类

书写自动智慧:探索Python文本分类器的开发与应用:支持二分类、多分类、多标签分类、多层级分类和Kmeans聚类 文本分类器,提供多种文本分类和聚类算法,支持句子和文档级的文本分类任务,支持二分类、多分类、多标签分类…

8月11日上课内容 nginx的多实例和动静分离

多实例部署 在一台服务器上有多个tomcat的服务。 配置多实例之前,看单个实例是否访问正常。 1.安装好 jdk 2.安装 tomcat cd /opt tar zxvf apache-tomcat-9.0.16.tar.gz mkdir /usr/local/tomcat mv apache-tomcat-9.0.16 /usr/local/tomcat/tomcat1 cp -a /usr…

使用Javassist实现热修复

工程目录图 请点击下面工程名称,跳转到代码的仓库页面,将工程 下载下来 Demo Code 里有详细的注释 代码:LearnRobustFix

【学习FreeRTOS】第5章——FreeRTOS任务挂起与恢复

1.任务的挂起与恢复的API函数 vTaskSuspend() ——挂起任务(类似暂停,可恢复,但删除任务,无法恢复)vTaskResume() ——恢复被挂起的任务xTaskResumeFromISR()—— 在中断中恢复被挂起的任务 1.1.任务挂起函数vTaskSu…

收银一体化-亿发2023智慧门店新零售营销策略,实现全渠道运营

伴随着互联网电商行业的兴起,以及用户理念的改变,大量用户从线下涌入线上,传统的线下门店人流量急剧收缩,门店升级几乎成为了每一个零售企业的发展之路。智慧门店新零售收银解决方案是针对传统零售企业面临的诸多挑战和问题&#…

谷歌全栈多平台应用开发神器Project IDX来了!PaLM 2加持,代码效率翻倍

一直以来,从0开始构建应用,都是一项复杂的工作。尤其是跨越手机、Web和桌面平台的程序。 这是一片无尽的复杂海洋,需要把技术堆栈融合在一起,来引导、编译、测试、部署、监控应用程序。 多年来,谷歌一直致力于让多平…

批量操作安装功能

功能结构设计: 分别使用单线程、多线程、多进程、协程分别实现功能: 一、 单线程实现功能 1.1单线程 实现发送点击生成 transaction_id; click01.py : 发送点击模块; base.py: 封装一些公共的方法&…

2023下半年软考改成机考,对考生有哪些影响?

软考改革成无纸化考试已经实锤。根据陕西软考办官网的消息,从2023年11月起,软考的所有科目都将改为机器考试形式。详情请参阅: 那么软考考试改为机考后,对我们会有哪些影响呢?我来简单概括一下。 1、复习的方法可以根…

苍穹外卖day12笔记

一、工作台 联系昨天 要实现的功能和昨天差不多,都是查询数据。 所以我们就写出查询语句,然后直接导入已经写好的代码。 实现效果 查询语句 今日数据 营业额 select count(amount) from orders where status5 and order_time > #{begin} and …