Java项目实战记录:雷达数据插值

news2024/11/26 8:46:01

Java项目实战记录:雷达数据插值

业务背景

之前已经实现了雷达数据的解析和雷达数据后端渲染功能,现在又有一个新的需求。之前是将雷达数据点使用GeoTools渲染成PNG的图片,但这个数据返给前端后不能无极缩放,因为它是个栅格图片;并且如果前端直接渲染雷达点数据也不行,渲染后的数据放大会变成稀疏的点。因此要无极缩放并且不能稀疏,这样的话就需要使用插值方法了,使用插值方法将雷达点数据插值成等值面,这样前端只需要渲染等值面即可。

插值方法

Kriging插值法

克里金插值法是一种基于统计学的插值方法,又称空间局部插值法,原理是利用区域化变量为基础,以变异函数为基本工具,对未知样点进行线性无偏、最优化估计。主要包括计算样本变异函数、根据变异函数对待估计数据建模、利用所建模型进行克里金插值估计和估计方差四大部分。

理论变异函数的基本公式为: ( ,ℎ)=1/2 {[ ( )− ( +ℎ)]^2 }

( )和 ( +ℎ)分别是在点x、x+h处的观测值,h为步长;{[ ( )− ( +ℎ)]^2}为方差。

理论变异函数模型有:线性模型、指数模型、球面模型等。讲过大量实验,系统拟选取球状模型作为理论变异函数:

img

实验变异函数r(h)反映了区域化变量的空间自相关性:

img

其中,h为监测点之间的空间间隔距离;N(h)为距离等于h的点对数;Z( )为处于点 处变量的观测值;Z( +h)为与点偏离h处变量的实测值。

假设 0为未观测点, ( =1,2,…, )为其周围的观测点,Z表示计算的区域化变量,则对 0处某个区域化变量的估计值可以写为:

img

IDW插值法

反距离权重 (IDW) 插值:彼此距离较近的事物要比彼此距离较远的事物更相似。当为任何未测量的位置预测值时,反距离权重法会采用预测位置周围的测量值。与距离预测位置较远的测量值相比,距离预测位置最近的测量值对预测值的影响更大。反距离权重法假定每个测量点都有一种局部影响,而这种影响会随着距离的增大而减小。由于这种方法为距离预测位置最近的点分配的权重较大,而权重却作为距离的函数而减小,因此称之为反距离权重法。

img

代码实现

wContour

这里的插值方法,我使用的是wContour

wContour库专为地球科学数据分析而设计,支持等高线的生成和操作。等高线,也称作等值线,是一种表示三维空间中相同数值的连续线,在地图上显示为连接所有具有相同数据值的点,常用于气象、地质和其他地球科学领域来展示温度、降水、高度等数据的空间分布。以下是wContour库的一些关键特点和功能:

  1. 语言支持:wContour库提供了Java和C#版本,方便在不同的编程环境中使用,使得开发者可以在Java或.NET平台上集成等高线功能。

  2. 等高线生成:库提供了生成等高线的算法,这些算法可以从栅格数据或散点数据中计算出等高线。这意味着你可以从具有不同空间分辨率的数据集中生成等高线,无论数据是规则还是不规则分布的。

  3. 等高线填充:除了生成等高线外,wContour还支持等高线填充功能,允许开发者在等高线之间使用不同的颜色或图案进行填充,以便更直观地表示不同的数据区间。这在制作地图或地球科学数据可视化时非常有用。

  4. 算法优化:wContour的等高线算法经过优化,能够处理大规模数据集,保证了处理速度和效率,即使是复杂或大尺度的数据集也能快速生成等高线。

  5. 数据裁剪和转换:该库还提供了数据裁剪和转换工具,允许开发者裁剪出感兴趣的区域或将数据从一种格式转换为另一种格式,以适应不同的分析需求。

  6. 多种应用场景:wContour的应用场景广泛,包括气象学、海洋学、地质学、环境科学等多个领域,可以用于制作气候地图、地形图、环境监测图等。

img

wContour打包成maven

  1. 从官网下载源码

image-20240317130313724

  1. 下载相关依赖,使用mvn命令打包成jar包,如果使用idea可以如下图所示来打包

image-20240317130634792

image-20240317130759912

  1. 使用mvn命令打包到本地maven仓库中,方便项目pom引入
mvn install:install-file -Dfile=D:\code\jar\wContour\wContour-1.7.1.jar -DgroupId=com.github -DartifactId=wContour -Dversion=1.7.1 -Dpackaging=jar

在maven项目中使用

        <dependency>
            <groupId>com.github</groupId>
            <artifactId>wContour</artifactId>
            <version>1.7.1</version>
        </dependency>

核心代码

将计算所需要的点和插值范围传入,通过wContour使用IDW进行计算,具体步骤如下所示:

    /**
     * 生成等值面
     *
     * @param radarDataPojo 训练数据
     * @param dataInterval  数据间隔
     * @param size          大小,矩形分割的大小,越大越精准
     * @param wktBoundary   插值范围 wkt
     * @return 等值面JSON字符串
     */
    public ArrayList<BisProductData> equivalentSurface(RadarDataPojo radarDataPojo,
                                                  double[] dataInterval,
                                                  int[] size,
                                                  String wktBoundary) {
        long start = System.currentTimeMillis();
        ArrayList<BisProductData> res = new ArrayList<>();

        ArrayList<LonLatData> list = radarDataPojo.getLonLatDataList();

        double[][] trainData = new double[list.size()][3];
        for (int i = 0; i < list.size(); i++) {
            trainData[i][0] = list.get(i).getLon();
            trainData[i][1] = list.get(i).getLat();
            trainData[i][2] = list.get(i).getVal();
        }

        try {
            double _undefData = -9999.0;
            SimpleFeatureCollection polygonCollection = null;
            List<PolyLine> cPolylineList = new ArrayList<PolyLine>();
            List<Polygon> cPolygonList = new ArrayList<>();

            int width = size[0],
                    height = size[1];
            double[] _X = new double[width];
            double[] _Y = new double[height];

            // 解析WKT字符串
            WKTReader reader = new WKTReader();
            Geometry boundaryGeom = reader.read(wktBoundary);
            // 2. 获取边界的最小和最大坐标
            double minX = boundaryGeom.getEnvelopeInternal().getMinX();
            double minY = boundaryGeom.getEnvelopeInternal().getMinY();
            double maxX = boundaryGeom.getEnvelopeInternal().getMaxX();
            double maxY = boundaryGeom.getEnvelopeInternal().getMaxY();
            // 3. 创建网格
            Interpolate.createGridXY_Num(minX, minY, maxX, maxY, _X, _Y);

            double[][] _gridData = new double[width][height];

            int nc = dataInterval.length;
            // 4. 进行插值计算(IDW 插值)
            _gridData = Interpolate.interpolation_IDW_Neighbor(trainData,
                    _X, _Y, 12, _undefData);
            int[][] S1 = new int[_gridData.length][_gridData[0].length];

            // 5. 提取轮廓线
            List<Border> _borders = Contour.tracingBorders(_gridData, _X, _Y,
                    S1, _undefData);
            // 6. 生成等值线
            cPolylineList = Contour.tracingContourLines(_gridData, _X, _Y, nc,
                    dataInterval, _undefData, _borders, S1);
            // 7. 对等值线进行平滑
            cPolylineList = Contour.smoothLines(cPolylineList);// 平滑
            // 8. 生成等值面
            cPolygonList = Contour.tracingPolygons(_gridData, cPolylineList,
                    _borders, dataInterval);
            // 9. 将生成的等值面转换为 GeoJSON 格式的字符串
             res = getPolygonGeoJsonList(cPolygonList);
            logger.info("差值成功, 共耗时" + (System.currentTimeMillis() - start) + "ms");
        } catch (Exception e) {
            logger.error("Error during calculation of equivalentSurface", e);
        }

        return res;
    }

完整代码

VectorInterpolation插值工具类
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zykj.radar_server.datahandle.pojo.LonLatData;
import com.zykj.radar_server.entity.BisProductData;
import com.zykj.radar_server.entity.pojo.RadarDataPojo;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wcontour.Contour;
import wcontour.Interpolate;
import wcontour.global.Border;
import wcontour.global.PointD;
import wcontour.global.PolyLine;
import wcontour.global.Polygon;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * 矢量插值方法
 * <p>
 * 使用IDW进行插值
 */
public class VectorInterpolation {

    private static final Logger logger = LoggerFactory.getLogger(VectorInterpolation.class);


    /**
     * 生成等值面
     *
     * @param radarDataPojo 训练数据
     * @param dataInterval  数据间隔
     * @param size          大小,矩形分割的大小,越大越精准
     * @param wktBoundary   插值范围 wkt
     * @return 等值面JSON字符串
     */
    public ArrayList<BisProductData> equivalentSurface(RadarDataPojo radarDataPojo,
                                                  double[] dataInterval,
                                                  int[] size,
                                                  String wktBoundary) {
        long start = System.currentTimeMillis();
        ArrayList<BisProductData> res = new ArrayList<>();

        ArrayList<LonLatData> list = radarDataPojo.getLonLatDataList();

        double[][] trainData = new double[list.size()][3];
        for (int i = 0; i < list.size(); i++) {
            trainData[i][0] = list.get(i).getLon();
            trainData[i][1] = list.get(i).getLat();
            trainData[i][2] = list.get(i).getVal();
        }

        try {
            double _undefData = -9999.0;
            SimpleFeatureCollection polygonCollection = null;
            List<PolyLine> cPolylineList = new ArrayList<PolyLine>();
            List<Polygon> cPolygonList = new ArrayList<>();

            int width = size[0],
                    height = size[1];
            double[] _X = new double[width];
            double[] _Y = new double[height];

            // 解析WKT字符串
            WKTReader reader = new WKTReader();
            Geometry boundaryGeom = reader.read(wktBoundary);
            // 2. 获取边界的最小和最大坐标
            double minX = boundaryGeom.getEnvelopeInternal().getMinX();
            double minY = boundaryGeom.getEnvelopeInternal().getMinY();
            double maxX = boundaryGeom.getEnvelopeInternal().getMaxX();
            double maxY = boundaryGeom.getEnvelopeInternal().getMaxY();
            // 3. 创建网格
            Interpolate.createGridXY_Num(minX, minY, maxX, maxY, _X, _Y);

            double[][] _gridData = new double[width][height];

            int nc = dataInterval.length;
            // 4. 进行插值计算(IDW 插值)
            _gridData = Interpolate.interpolation_IDW_Neighbor(trainData,
                    _X, _Y, 12, _undefData);
            int[][] S1 = new int[_gridData.length][_gridData[0].length];

            // 5. 提取轮廓线
            List<Border> _borders = Contour.tracingBorders(_gridData, _X, _Y,
                    S1, _undefData);
            // 6. 生成等值线
            cPolylineList = Contour.tracingContourLines(_gridData, _X, _Y, nc,
                    dataInterval, _undefData, _borders, S1);
            // 7. 对等值线进行平滑
            cPolylineList = Contour.smoothLines(cPolylineList);// 平滑
            // 8. 生成等值面
            cPolygonList = Contour.tracingPolygons(_gridData, cPolylineList,
                    _borders, dataInterval);
            // 9. 将生成的等值面转换为 GeoJSON 格式的字符串
             res = getPolygonGeoJsonList(cPolygonList);
            logger.info("差值成功, 共耗时" + (System.currentTimeMillis() - start) + "ms");
        } catch (Exception e) {
            logger.error("Error during calculation of equivalentSurface", e);
        }

        return res;
    }


    private ArrayList<BisProductData> getPolygonGeoJsonList(List<Polygon> cPolygonList) {

        ArrayList<BisProductData> res = new ArrayList<>();
//        List<String> geoJsonList = new ArrayList<>();

        // 如果多边形列表为空,返回空列表
        if (cPolygonList == null || cPolygonList.isEmpty()) {
            return res;
        }

        try {
            for (Polygon pPolygon : cPolygonList) {
                BisProductData bisProductData = new BisProductData();
                List<Object> ptsTotal = new ArrayList<>();
                List<Object> pts = new ArrayList<>();

                PolyLine pline = pPolygon.OutLine;
                for (PointD ptD : pline.PointList) {
                    List<Double> pt = new ArrayList<>();
                    pt.add(ptD.X);
                    pt.add(ptD.Y);
                    pts.add(pt);
                }

                ptsTotal.add(pts);

                if (pPolygon.HasHoles()) {
                    for (PolyLine cptLine : pPolygon.HoleLines) {
                        List<Object> cpts = new ArrayList<>();
                        for (PointD ccptD : cptLine.PointList) {
                            List<Double> pt = new ArrayList<>();
                            pt.add(ccptD.X);
                            pt.add(ccptD.Y);
                            cpts.add(pt);
                        }
                        if (!cpts.isEmpty()) {
                            ptsTotal.add(cpts);
                        }
                    }
                }

                Map<String, Object> geometry = new HashMap<>();
                geometry.put("type", "Polygon");
                geometry.put("coordinates", ptsTotal);

                String geometryJson = new ObjectMapper().writeValueAsString(geometry);


                double hv = pPolygon.HighValue;
                double lv = pPolygon.LowValue;

                bisProductData.setGeom(geometryJson);
                bisProductData.setHvalue(hv);
                bisProductData.setLvalue(lv);

                res.add(bisProductData);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(res.get(0));
        return res;
    }


    /**
     * 将指定的 JSON 字符串追加到文件末尾。
     *
     * @param strFile 要追加内容的文件路径
     * @param strJson 要追加的 JSON 字符串
     */
    public static void append2File(String strFile, String strJson) {
        // 创建文件对象
        File f = new File(strFile);

        // 文件写入流
        FileWriter fw;
        try {
            // 初始化文件写入流
            fw = new FileWriter(f);

            // 将 JSON 字符串写入文件
            fw.write(strJson);

            // 关闭文件写入流
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
测试方法

这里使用的是之前的雷达数据

    @Test
    public void testGeom() {

        long start = System.currentTimeMillis();

        VectorInterpolation equiSurface = new VectorInterpolation();

        ArrayList<LonLatData> list = RadarDataParser.handlePolarProduct("C:\\data\\雷达测试数据\\数据\\20190305_110801_ZHBJ_Z_VOL_2.50.dat");
        double[][] trainData = new double[list.size()][3];
        for (int i = 0; i < list.size(); i++) {
            trainData[i][0] = list.get(i).getLon();
            trainData[i][1] = list.get(i).getLat();
            trainData[i][2] = list.get(i).getVal();
        }


        double[] dataInterval = new double[]{-10, -5, 0, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70};

        String boundryFile = "D:\\temp\\layers\\POLYGON.shp";

        int[] size = new int[]{200, 200};

        boolean isclip = false;

        try {
            String strJson = equiSurface.equivalentSurface(trainData, dataInterval, size, boundryFile, isclip);
//            System.out.println(strJson);
            String strFile = "D:\\temp\\layers\\20200618_073326_ZHBJ_Z_VOL_250_100.json";
            VectorInterpolation.append2File(strFile, strJson);
            System.out.println(strFile + "差值成功, 共耗时" + (System.currentTimeMillis() - start) + "ms");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

效果

使用IDW插值生成的效果如下所示:

image-20240317132504552

根据等值面的值进行渲染,效果如下所示:

image-20240317132618141

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

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

相关文章

ArmSoM-Sige RK3588开发板使用手册

Sige7 使用手册&#xff0c;帮助用户了解Sige7的基本使用和需要的准备工作。 当您拿到产品的时候&#xff0c;您需要知道它的型号以及硬件版本&#xff0c;这些信息都可以在板子上的丝印找到。我们会尽可能详细地向您介绍产品的信息。 入门准备​ 在开始使用 ArmSoM-Sige7 之…

matlab空间曲线图形

说明&#xff1a;问题来自CSDN-问答板块&#xff0c;题主提问。 需求&#xff1a;如何用子图命令画出平面y2z&#xff0c;z2y与球面x^2y^2z^25相交的空间曲线图形。需要完整代码和结果的图片。 一、先看效果图 二、代码 % 创建figure figure% 创建二维网格&#xff0c;用于定…

数据结构的概念大合集03(栈)

概念大合集03 1、栈1.1 栈的定义和特点1.2 栈的基础操作1.3 栈的顺序存储1.3.1 顺序栈1.3.2 栈空&#xff0c;栈满&#xff0c;进栈&#xff0c;出栈的基本思想1.3.3 共享栈1.3.3.1 共享栈的4要素 1.4 栈的链式存储1.4.1 链栈的实现1.4.2 链栈的4个要素 1、栈 1.1 栈的定义和特…

酷开系统用电视为居家生活打开精彩窗口|酷开科技|酷开会员|

随着互联网的发展&#xff0c;电视也承载了更多的功能。相比于传统的电视&#xff0c;如今的智能电视屏幕更大、分辨率更高、色彩更加鲜艳&#xff0c;能够呈现出更加逼真的画面效果。当观众观看大屏电视时&#xff0c;仿佛置身于电影大幕的场景之中&#xff0c;感受到更为震撼…

边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 -- 整体介绍(一)

专栏目录 边缘计算WEB端应用融合&#xff1a;AI行为识别智能监控系统搭建指南 – 整体介绍&#xff08;一&#xff09; 边缘计算WEB端应用融合&#xff1a;AI行为识别智能监控系统搭建指南 – 边缘设备图像识别及部署&#xff08;二&#xff09; 边缘计算WEB端应用融合&#xf…

洛谷_P2404 自然数的拆分问题_python写法

P2404 自然数的拆分问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路记录&#xff1a; 这道题是一道简单的DFS。 n int(input()) data [0 for _ in range(110)] def dfs(sum, p, cnt):if sum>n:returnif sum n:print(data[0],end)for i in range(1,cnt):print(f{…

centos7安装jdk详细步骤(yum安装与手动安装)

centos7安装jdk详细步骤&#xff08;yum安装与手动安装&#xff09; 一、使用yum安装1. 准备工作2. 检查系统是否自带jdk3. 安装jdk 二、手动安装jdk1. 下载上传jdk2. 安装jdk3. 配置环境变量 一、使用yum安装 1. 准备工作 如果你的机器可以联网可以使用此方法 ping www.baidu…

YOLOv7 | 添加GSConv,VoVGSCSP等多种卷积,有效提升目标检测效果,代码改进(超详细)

⭐欢迎大家订阅我的专栏一起学习⭐ &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; YOLOv5涨点专栏&#xff1a;http://t.csdnimg.cn/QdCj6 YOLOv7专栏&#xff1a; http://t.csdnimg.cn/dy…

51-31 CVPR’24 | VastGaussian,3D高斯大型场景重建

2024 年 2 月&#xff0c;清华大学、华为和中科院联合发布的 VastGaussian 模型&#xff0c;实现了基于 3D Gaussian Splatting 进行大型场景高保真重建和实时渲染。 Abstract 现有基于NeRF大型场景重建方法&#xff0c;往往在视觉质量和渲染速度方面存在局限性。虽然最近 3D…

Git小乌龟安装及使用教程

一、Win7安装git 软件下载地址&#xff1a;git for windows 安装过程直接默认下一步&#xff0c;直到安装结束。 安装结束后重启一下。 安装完成后&#xff0c;在文件夹空白处右键出现以下几个标识&#xff0c;说明安装成功。 二、安装tortoise git&#xff08;乌龟git&…

flutter 局部view更新,dialog更新进度,dialog更新

局部更新有好几种方法&#xff0c;本次使用的是 StatefulBuilder 定义 customState去更新对话框内容 import package:flutter/cupertino.dart; import package:flutter/material.dart;class ProgressDialog {final BuildContext context;BuildContext? dialogContext;double _…

帮助读者掌握C语言编程基础知识的书籍

帮助读者掌握C语言编程的基础知识&#xff0c;了解如何将人工智能技术应用于自己的编程项目。 人工智能编程&#xff08;赋能C语言&#xff09; 作者&#xff1a; 黄箐、廖云燕、曾锦山、邢振昌 ISBN号&#xff1a; 9787302648796 出版日期&#xff1a; 2023-11-01 本书以C…

【linux】环境变量(进程二)

这里写目录标题 命令行参数&#xff1a;环境变量&#xff1a; 命令行参数&#xff1a; 不谈命令行参数就谈环境变量就是耍流氓。 相信我们在C语言阶段都在main函数里见过参数。 例如int main(int argc, char* argv[]) 这是什么东西呢&#xff1f; 话不多说我们直接打印一下看…

Vue2(八):脚手架结构、render函数、ref属性、props配置项、mixin(混入)、插件、scoped样式

一、脚手架结构分析 crlc终止刚刚搭建的vue。 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ …

利用WebGL绘制简单几何

利用WebGL绘制最简单的几何图形 一、WebGL简介 WebGL是一种用于在网页上渲染交互式3D和2D图形的JavaScript API。它基于OpenGL ES 2.0&#xff0c;提供了一种在浏览器中使用硬件加速图形的方式。 二、图形系统绘图流程 图形系统的通用绘图流程会包括六个部分&#xff1a; …

python_django网红基地孵化园场地管理系统flask

作为一个管理孵化园的网络系统&#xff0c;数据流量是非常大的&#xff0c;所以系统的设计必须满足使用方便&#xff0c;操作灵活的要求。所以在设计孵化园管理系统管理系统应达到以下目标&#xff1a; &#xff08;1&#xff09;界面要美观友好&#xff0c;检索要快捷简易&…

python问题:vscode切换环境,pip安装库网络错误,不使用anaconda安装库

python问题&#xff1a;vscode切换环境&#xff0c;pip安装库网络错误 vscode切换环境pip安装库网络错误 不使用anaconda安装库 记录一下遇见的python问题。 vscode切换环境 在vscode上面的搜索框输入 > select interpreter然后选择需要的环境。 pip安装库网络错误 用…

数据丢失怎么办?不可不知道的3个恢复方法分享!

“作为一名电脑小白&#xff0c;刚买了电脑后我就把所有学习资料都保存在电脑上了&#xff0c;刚刚发现有部分比较重要的数据找不到了&#xff0c;我应该怎么操作才能恢复这些文件呢&#xff1f;” 数据丢失&#xff0c;对于任何个人或企业来说&#xff0c;都是一件令人头疼的事…

Python学习从0到1 day17 Python异常、模块、包

不走心的努力&#xff0c;都是在敷衍自己 ——24.3.19 万字长文&#xff0c;讲解异常、模块、包&#xff0c;看这一篇就足够啦 什么是异常? 当检测到一个错误时&#xff0c;python解释器就无法继续执行了&#xff0c;反而出现了一些错误的提示&#xff0c;这就是所谓的异常&am…

「滚雪球学Java」:安全(章节汇总)

&#x1f3c6;本文收录于「滚雪球学Java」专栏&#xff0c;专业攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎大家关注&&收藏&#xff01;持续更新中&#xff0c;up&#xff01;up&#xff01;up&#xff01;&#xf…