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

        很多时候我们需要某个区域的正射图,虽然正射图一般都运用了匀色的算法,整体色彩比较均衡。但如果研究区内有大量的植被,这个时候植被突出显示就很有必要了。所以今天给大家分享一下使用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)  # 打开数据集datasetds_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)  # 打开数据集datasetds_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.2for 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)  # 将无效值设为0ds_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)  # 打开数据集datasetds_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 = 0chance = int(input("请选择增强算法:1:GLI, 2:RGBVI\n"))if chance == 1:array_new_green = array_green + array_green*GLIelif chance == 2:array_new_green = array_green*0.8+RGBVI*0.2*255else: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)  # 将无效值设为0ds_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)  # 打开数据集datasetds_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)  # 打开数据集datasetds_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.2for 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)  # 将无效值设为0ds_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 dsdef 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)  # 打开数据集datasetds_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 = 0chance = int(input("请选择增强算法:1:GLI, 2:RGBVI\n"))if chance == 1:array_new_green = array_green + array_green*GLIelif chance == 2:array_new_green = array_green*0.8+RGBVI*0.2*255else: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)  # 将无效值设为0ds_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.hqwc.cn/news/62626.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s的yaml文件管理

声明式管理方法: 1.适合于对资源的修改操作2.声明式资源管理方法依赖于资源配置清单文件对资源进行管理资源配置清单文件有两种格式:yaml(人性化,易读),json(易于api接口解析)3.对资…

内存快照:宕机后,Redis如何实现快速恢复?RDB

AOF的回顾 回顾Redis 的AOF的持久化机制。 Redis 避免数据丢失的 AOF 方法。这个方法的好处,是每次执行只需要记录操作命令,需要持久化的数据量不大。一般而言,只要你采用的不是 always 的持久化策略,就不会对性能造成太大影响。 …

伪原创神码ai怎么样【php源码】

这篇文章主要介绍了python汉化补丁包下载,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。 火车头采集ai伪原创插件截图: ** Spyder汉化(python汉化&…

打造个性化观影盛宴:对实时多兴趣召回的探索

包括 Tubi 在内的广告型点播流媒体服务,正在成为免费在线消费娱乐的重要组成部分。Tubi 拥有一个囊括电视剧、电影、体育和娱乐直播频道的海量视频内容库;同时,Tubi 为观众提供个性化的视频推荐,帮助观众快速找到想看的视频内容&a…

(一)创建型设计模式:3、建造者模式(Builder Pattern)

目录 1、建造者模式含义 2、建造者模式的讲解 3、使用C实现建造者模式的实例 4、建造者模式的优缺点 5、建造者模式VS工厂模式 1、建造者模式含义 The intent of the Builder design pattern is to separate the construction of a complex object from its representatio…

整理mongodb文档:改

个人博客 整理mongodb文档:改 求关注,求批评,求进步 文章概叙 本文主要讲的是mongodb的updateOne以及updateMany,主要还是在shell下进行操作,也讲解下主要的参数upsert以及更新的参数。 数据准备 本次需要准备的数据不是很多…

python --windows获取启动文件夹路径/获取当前用户名/添加自启动文件

如何使用Python获取计算机用户名 一、Python自带的getpass模块可以用于获取用户输入的密码,但是它同样可以用来获取计算机用户名。 import getpassuser getpass.getuser() print("计算机用户名为:", user)二、使用os模块获取用户名 Python的…

Centos7.9系统_亲测成功_磁盘满了_分区和挂载新盘_创建文件夹并挂载分区---Linux工作笔记057

由于在某些部署环境下,运维管理员,仅仅是给分配一些硬盘容量,但是并没有进行分区和挂载到对应的合适的目录下,因此这个时候就需要我们自己去处理了. 这个是自己亲测成功的:由于是后面记录的,尽量记录详细 free -h 查看一下内存情况 df -h查看 硬盘的使用情况,还有是否有没挂载…

以数据为中心的标记语言--yaml

😀前言 本篇博文是关于以数据为中心的配置文件yaml的说明和应用,希望能够帮助到您😊 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家&…

设计模式--策略模式

目录 一.场景 1.1场景 2.2 何时使用 2.3个人理解 二. 业务场景练习 2.1业务: 2.2具体实现 2.3思路 三.总结 3.1策略模式的特点: 3.2策略模式优点 3.3策略模式缺点 一.场景 1.1场景 许多相关的类仅仅是行为有异,也就是说业务代码需要根据场景不…

物联网的定义、原理、示例、未来

什么是物联网? 物联网 (IoT) 是指由嵌入传感器、软件和网络连接的物理设备、车辆、电器和其他物理对象组成的网络,允许它们收集和共享数据。这些设备(也称为“智能对象”)的范围可以从简单的“智能家居”设备(如智能恒温器)到可穿戴设备(如智能手表和支持RFID的服…

C++:string类模拟实现

C:string类模拟实现 成员变量构造和析构容量相关1.获取容器大小(_size)和容量(_capacity)2.扩容(reserve)3.更改容器大小 修改相关1.尾插2.指定位置插入3.指定位置删除4.清空5.交换两个对象 比较相关访问相关迭代器相关查找相关其它成员函数1.截取子串2.取得C格式字…