C# 读取四波段遥感影像生成植被覆盖度栅格(TIF)

news/2024/11/15 18:06:42/文章来源:https://www.cnblogs.com/turingguo/p/18547683

GDAL使用

使用gdal.netcore来读取和生成栅格文件。
优点:自带gdal运行时相关文件,不用额外再安装gdal库
缺点:导致发布的文件变大很多,比如Win+Linux的运行时加起来就超过了400M,所以最好是按需加载对应的运行时。比如DEBUG是运行在win的,就添加MaxRev.Gdal.WindowsRuntime.Minimal包,然后Release环境是运行在linux x64的,就添加MaxRev.Gdal.LinuxRuntime.Minimal.x64

系统 运行时
windows MaxRev.Gdal.WindowsRuntime.Minimal
linux-x64 MaxRev.Gdal.WindowsRuntime.Minimal
linux-arm64 MaxRev.Gdal.WindowsRuntime.Minimal
mac-x64 MaxRev.Gdal.WindowsRuntime.Minimal
mac-arm64 MaxRev.Gdal.WindowsRuntime.Minimal

如图所示,仅支持64位系统。
还有就是太老的系统不支持,比如centOS7,那就只能是源码编译安装Gdal(比较折腾的过程),然后再单独修改gdal注册相关的代码。不过老系统更推荐的做法是使用docker,基础容器镜像使用较新的系统版本,比如debian 12之类的。

可以通过msbuild condition比较编译时的提供的环境变量来引用不同的运行时包

  <ItemGroup Condition="'$(TargetRuntime)'=='win'"><PackageReference Include="MaxRev.Gdal.WindowsRuntime.Minimal" /></ItemGroup><ItemGroup Condition="'$(TargetRuntime)'=='lin-x64'"><PackageReference Include="MaxRev.Gdal.LinuxRuntime.Minimal.x64" /></ItemGroup>

然后在dotnet build或publish时传入对应的参数 -p:TargetRuntime=win-p:TargetRuntime=lin-x64

计算FVC

计算方法如下,读取卫星遥感影像的3、4波段,计算NDVI值中的5%和95%值作为极值,然后再根据极值计算FVC。
由于单个tif文件可能极大,所以第一次计算NDVI极值时不存计算出的NDVI值(一个省的10m分辨率影像就近100G了)
后续计算FVC时每次只读取缓冲区大小的数据进行计算。
缺点是串行计算十分缓慢,直接使用Task.WhenAll又会导致读取栅格报错protected memory。可能在读取和写入栅格数据时进行加锁处理是可行的。

参数是遥感影像栅格和FVC结果栅格的路径,返回值是遥感影像栅格的大小、坐标系、地理变换等信息。

    /// <summary>/// 基于哨兵四波段遥感卫星影像(B\G\R\NIR),计算植被归一化指数(NDVI) 基于NDVI,计算植被覆盖度FVC/// </summary>/// <param name="tifPath">遥感影像路径</param>/// <param name="resultTifPath">FVC栅格路径</param>private (double[] transform, int xSize, int ySize, SpatialReference srs, string projection) Fvc(string tifPath,string resultTifPath){Console.WriteLine($"{DateTime.Now: mm:ss} 开始计算FVC");using var ds = Gdal.Open(tifPath, Access.GA_ReadOnly);using var driver = Gdal.GetDriverByName("GTiff");using var bandR = ds.GetRasterBand(3);using var bandNIR = ds.GetRasterBand(4);//NDVI=float(band4-band3)/(band4+band3)//FVC=(NDVI-bandmin)/(bandmax-bandmin) bandmin取NDVI中累计值为最接近5%的值,bandmax取NDVI中累计值为最接近95%的值,FVC计算结果应为0~1区间,计算结果中存在小于0的值归为0,存在大于1的值归为1//设置缓冲区2048*2048,每次只从4个波段中读取对应缓冲区的数据进行计算var xSize = ds.RasterXSize;var ySize = ds.RasterYSize;var blockSize = 2048;var xCount = (int)Math.Ceiling((float)xSize / blockSize);var yCount = (int)Math.Ceiling((float)ySize / blockSize);bandR.GetNoDataValue(out var noDataValue, out _);if (File.Exists(resultTifPath)) File.Delete(resultTifPath);var transform = new double[6];ds.GetGeoTransform(transform);ConcurrentDictionary<double, int> nvdiSet = new();for (int y = 0; y < yCount; y++){var bufferR = new List<double[]>(xCount);var bufferNIR = new List<double[]>(xCount);for (int x = 0; x < xCount; x++){var offsetX = x * blockSize;var offsetY = y * blockSize;var actualWidth = Math.Min(blockSize, Math.Max(xSize - offsetX, 0));var actualHeight = Math.Min(blockSize, Math.Max(ySize - offsetY, 0));bufferR.Add(new double[actualWidth * actualHeight]);bandR.ReadRaster(offsetX, offsetY, actualWidth, actualHeight, bufferR[x], actualWidth, actualHeight, 0,0);bufferNIR.Add(new double[actualWidth * actualHeight]);bandNIR.ReadRaster(offsetX, offsetY, actualWidth, actualHeight, bufferNIR[x], actualWidth, actualHeight,0, 0);}//计算NDVIfor (var i = 0; i < xCount; i++){var index = i;for (var j = 0; j < bufferR[index].Length; j++){var r = bufferR[index][j];var nir = bufferNIR[index][j];if (double.IsNaN(r) || double.IsNaN(nir)) continue;var ndvi = (nir - r) / (nir + r);if (double.IsNaN(ndvi)) continue;nvdiSet.AddOrUpdate(Math.Round(ndvi, 5), 1, (key, oldValue) => oldValue + 1);}}}//计算5%和95%对应的Countvar totalCount = nvdiSet.Sum(d => d.Value);var ndviMin = GetPercentCount(totalCount, 0.05, nvdiSet.OrderBy(d => d.Key));var ndviMax = GetPercentCount(totalCount, 0.05, nvdiSet.OrderByDescending(d => d.Key));using var dsResult = driver.Create(resultTifPath, xSize, ySize, 1, DataType.GDT_Float32, null);var projection = ds.GetProjection();dsResult.SetProjection(projection);dsResult.SetGeoTransform(transform);var srs = ds.GetSpatialRef();dsResult.SetSpatialRef(srs);using var bandResult = dsResult.GetRasterBand(1);bandResult.SetNoDataValue(noDataValue);var ndviDiff = ndviMax - ndviMin;for (int y = 0; y < yCount; y++){//计算NDVIfor (var i = 0; i < xCount; i++){var index = i;var y1 = y;var offsetX = index * blockSize;var offsetY = y1 * blockSize;var actualWidth = Math.Min(blockSize, Math.Max(xSize - offsetX, 0));var actualHeight = Math.Min(blockSize, Math.Max(ySize - offsetY, 0));var bufferR = new double[actualWidth * actualHeight];bandR.ReadRaster(offsetX, offsetY, actualWidth, actualHeight, bufferR, actualWidth, actualHeight, 0,0);var bufferNIR = new double[actualWidth * actualHeight];bandNIR.ReadRaster(offsetX, offsetY, actualWidth, actualHeight, bufferNIR, actualWidth,actualHeight,0, 0);var dataResult = new double[bufferR.Length];for (var j = 0; j < bufferR.Length; j++){var r = bufferR[j];var nir = bufferNIR[j];if (double.IsNaN(r) || double.IsNaN(nir)) continue;var ndvi = (nir - r) / (nir + r);if (double.IsNaN(ndvi)) continue;var fvc = (ndvi - ndviMin) / ndviDiff;dataResult[j] =fvc < 0 ? NoDataValue :fvc > 1 ? 1 :fvc;}bandResult.WriteRaster(offsetX, offsetY, actualWidth, actualHeight, dataResult, actualWidth,actualHeight, 0, 0);}}return (transform, xSize, ySize, srs, projection);}

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

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

相关文章

js原型链污染

js原型链污染 原理介绍 对于语句:object[a][b] = value 如果可以控制a、b、value的值,将a设置为__proto__,我们就可以给object对象的原型设置一个b属性,值为value。这样所有继承object对象原型的实例对象在本身不拥有b属性的情况下,都会拥有b属性,且值为value。 可以通过…

基于米尔NXP i.MX93开发板OpenCV的相机捕捉视频进行人脸检测

本篇测评由优秀测评者“eefocus_3914144”提供。 本文将介绍基于米尔电子MYD-LMX93开发板(米尔基于NXP i.MX93开发板)的基于OpenCV的人脸检测方案测试。 OpenCV提供了一个非常简单的接口,用于相机捕捉一个视频(我用的电脑内置摄像头)1、安装python3-opencvapt install pyth…

hbase-2.2.7分布式搭建文档(附详细操作步骤命令及相关操作截图)

hbase-2.2.7分布式搭建文档 一,搭建前准备 1.检查是否已经安装JDK 2.搭建hbase前需要先搭建好hadoop 3.检查zookeeper是否正常启动 #启动zookeeper(三台都要启动) zkServer.sh start#查看zookeeper状态(一个leader两个follower) zkServer.sh status4.到官网或国内镜像站下载hb…

自动化构建镜像:Packer

在介绍Packer之前,先来回顾一下未使用Packer时自定义虚拟机镜像的步骤。先在本地启动一个虚拟机,从安装系统开始,再进行自定义配置或应用安装,最后封装压缩成镜像,详细操作步骤可以参考我之前写的文档,制作Centos 7镜像:https://robin-2016.github.io/2019/04/08/制作op…

牛逼!字节 IDE 来了!!

前言 大家好,我是R哥。 最近做面试辅导,很多同学和我抱怨说,去 XX 公司面试,刚进公司,面试官还没有见着呢,就让我先手撕两道算法题,做不出来的话直接 GG。 没错,如果你想拿一份还不错的收入,想去中大厂,特别是字节、阿里、腾讯这些一线大厂,面试前都会有一次算法笔试…

虚拟串口工具和串口调试工具详解 - 附下载地址

简介 串口开发过程中, 一般需要以下工具用于开发和调试:虚拟串口工具简介 虚拟串口软件, 可以在系统中虚拟出串口, 这样开发人员可以在没有物理串口设备的情况下进行开发. 串口调试工具简介 串口调试工具主要用于给串口发送信息, 测试串口是否连通, 发送消息是否正常被接收等.本…

怎么用云游戏玩Steam?ToDesk云电脑新手入门教程

对于新手玩家来说,想要上手Steam游戏,这门槛真有点高。不说要从众多真假难辨的软件中找出正版,遇到Steam内想玩的游戏还得等着下载安装解压,费时又费力。玩家想解决这个困难也很简单,只需下个ToDesk云游戏即可。它是ToDesk云电脑中专门玩游戏的版块,预安装了上百款热门游…

Vuex与Redux比较

由于Vuex和Redux都是从Flux中衍生出来,同时Vuex对Redux部分思想也有一些借鉴,所以Vuex和Redux有很多相同点。很多资料也有介绍两者的对比,但大部分讲解的比较抽象,较难理解。笔者整理两者异同点,同时配有标准案例进行说明。注意本文不是科普vuex和redux相关概念,相关知识…

第6篇 Scrum 冲刺博客

作业要求这个作业属于哪个课程 计科34班这个作业的要求在哪里 团队作业4——项目冲刺这个作业的目标 1.站立式会议2.发布项目燃尽图3.每人的代码/文档签入记录4.适当的项目程序/模块的最新(运行)截图5.每日每人总结会议照片昨日已完成的工作/今天计划完成的工作成员 昨天已完…

RabbitMQ 五种模式

RabbitMQ是一种常用的消息队列服务,它提供了五种消息模型:简单模型、工作队列模型、发布/订阅模型、路由模型、主题模型。1. 简单模型(Simple Message Queue,简称SQS):一个生产者,一个消费者,一个队列。 2. 工作队列模型(Work Queue):多个消费者共同处理一个队列中的…

如何防止手机被远程控制,安全远控推荐ToDesk

随着电子设备及各样应用的兴起,手机可以为人们带来的便利已越来越多,从二十年前的联络通话,到现如今的社交娱乐、导航、缴费等;通过智能手机中的软件均可轻松实现。 然而虽然手机的妙用有很多,但对于一些不太善用电子设备的中老年亲友来说,在使用中却也存在一定的被诈骗风…

Docker不再神秘 ------Ubuntu20.04 安装Docker 及实用技巧,建议收藏

Dockerdocker是一种容器,简而言之就是别人把一堆环境配置好了,你可以下载下来直接拿来使用(我的个人理解),有点像虚拟机你知道吧。比如下面这样,我直接打开了一个小电脑(docker),里面桌面啊、root啊全都有,跟你ubuntu系统类似,单说细节还不完全一样,毕竟它轻便哈哈…