首页 > 其他分享 >基于三维离散点插值的高度图方法

基于三维离散点插值的高度图方法

时间:2023-06-25 18:22:33浏览次数:113  
标签:p2 distance p1 pt p3 插值 float 三维 离散

在我读研时,导师的项目是做一个无人水质检测船。其目标之一是具备绘制水域的深度图的功能。基本流程是在调查水域时用无人船载着一个深度计记录水域各处的位置和深度${ \left( x,y,z \right) }$,然后根据测得的数据用LabView渲染成一个水域深度3D图。因为无人船测量深度数据的位置${ \left( x,y \right) }$是随机的,而LabView渲染3D数据需要数据按照网格排列(即二维数组的行与行、列与列之间是等距的),所以需要对无人船测量数据进行插值处理后再渲染。当时我采用的是基于径向基函数的拟合方法将随机数据插值成网格数据,效果不太好,因为径向基函数往往会在数据稀疏的地方形成一个凸起的轮廓。

偶然再次想起这个问题,虽然现在的我已不需要做这些事,但是解决这个问题可以使能力得到一些提升。经过查找,发现可以先用Delaunay三角剖分算法将测量数据拆分成一个个相邻的三角形,然后用三点线性插值法将数据修改成按网格排列的深度数据。这里不赘述理论,直接给出实现代码和效果。为了实现上的方便,本文的插值方法使用OpenCV实现,因为OpenCV已经封装好Delaunay三角剖分算法了;而3D曲面渲染使用LabView实现。OpenCV是64位的,LabView是32位的,二者通过控制台标准输入输出流共享数据。本文的运行环境是VS2017、OpenCV430和LabView2018(32位)。下面是CPP文件内容,实现了插值算法:

template<typename T1, typename T2>
float distance(const T1& p1, const T2& p2)
{
    return sqrtf((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

float interpolate(const Point3f& p1, const Point3f& p2, const Point3f& p3, const Point2f& pt)
{
    float d1 = 0.5f * (distance(p1, p2) + distance(p1, pt) + distance(p2, pt));
    float s1 = sqrtf(d1 * (d1 - distance(p1, p2)) * (d1 - distance(p1, pt)) * (d1 - distance(p2, pt)));
    float d2 = 0.5f * (distance(p1, p3) + distance(p1, pt) + distance(p3, pt));
    float s2 = sqrtf(d2 * (d2 - distance(p1, p3)) * (d2 - distance(p1, pt)) * (d2 - distance(p3, pt)));
    float d3 = 0.5f * (distance(p2, p3) + distance(p2, pt) + distance(p3, pt));
    float s3 = sqrtf(d3 * (d3 - distance(p2, p3)) * (d3 - distance(p2, pt)) * (d3 - distance(p3, pt)));
    float ssum = s1 + s2 + s3;
    float z = (s1 * p3.z + s2 * p2.z + s3 * p1.z) / ssum;
    return z;
}

void interpolate(const Point3f* points, int count, const Size& size, float* xs, float* ys, float* zs)
{
    vector<Point2f> xys;
    xys.reserve(count);
    for (int i = 0; i < count; i++)
    {
        xys.push_back(Point2f(points[i].x, points[i].y));
    }
    Rect rect = boundingRect(xys);
    Subdiv2D div(rect);
    for (int i = 0; i < count; i++)
    {
        div.insert(xys);
    }
    vector<Vec6f> tris;
    div.getTriangleList(tris);
    float hStep = rect.height / (size.height - 1.0f);
    float wStep = rect.width / (size.width - 1.0f);
    for (int i = 0; i < size.height; i++)
    {
        Point2f curr;
        curr.x = rect.x + i * hStep;
        xs[i] = curr.x;
        for (int j = 0; j < size.width; j++)
        {
            curr.y = rect.y + j * wStep;
            ys[j] = curr.y;
            auto found = std::find_if(tris.begin(), tris.end(),
                [&curr](Vec6f& pt3) { return pointPolygonTest(Mat(3, 1, CV_32FC2, pt3.val), curr, false) >= 0; });
            if (found != tris.end())
            {
                auto p1 = std::find_if(points, points + count,
                    [&found](const Point3f& p) { return p.x == (*found)[0] && p.y == (*found)[1]; });
                auto p2 = std::find_if(points, points + count,
                    [&found](const Point3f& p) { return p.x == (*found)[2] && p.y == (*found)[3]; });
                auto p3 = std::find_if(points, points + count,
                    [&found](const Point3f& p) { return p.x == (*found)[4] && p.y == (*found)[5]; });
                *zs = interpolate(*p1, *p2, *p3, curr);
            }
            else
            {
                *zs = 0;
            }
            zs++;
        }
    }
}

int main()
{
    int count;
    std::cin >> count;
    std::vector<Point3f> input;
    for (int i = 0; i < count; i++)
    {
        Point3f temp;
        std::cin >> temp.x >> temp.y >> temp.z;
        input.push_back(temp);
    }
    Size size;
    std::cin >> size.width >> size.height;

    std::vector<float> xs(size.height), ys(size.width);
    std::vector<float> zs(size.area());
    interpolate(input.data(), count, size, xs.data(), ys.data(), zs.data());

    for (auto& item : xs)
    {
        std::cout << item << " ";
    }
    std::cout << "\n";

    for (auto& item : ys)
    {
        std::cout << item << " ";
    }
    std::cout << "\n";

    for (auto& item : zs)
    {
        std::cout << item << " ";
    }
    std::cout << "\n";

    return 0;
}

在三角剖分之后的三点插值方法如下。图中A、B、C是已知点,O是待插值点:

用如下公式计算O点的深度值:

$${ O_{z}=\frac{S_{\bigtriangleup OBC}}{S_{\bigtriangleup ABC}}A_{z}+\frac{S_{\bigtriangleup OAC}}{S_{\bigtriangleup ABC}}B_{z}+\frac{S_{\bigtriangleup OAB}}{S_{\bigtriangleup ABC}}C_{z} }$$

下面是LabView端的程序和界面截图。主要方法就是使用LabView的“执行系统命令”函数执行上方的C++控制台程序,把输入数据转换成字符串作为标准输入传入,程序处理之后在标准输出上打印结果,LabView读取标准输出得到结果然后显示结果。由于验证用的点比较少只有8个点,所以3D曲面看起来非常生硬:

 

标签:p2,distance,p1,pt,p3,插值,float,三维,离散
From: https://www.cnblogs.com/mengxiangdu/p/17502500.html

相关文章

  • 【tensorflow】连续输入+离散输入的神经网络模型训练代码
    【tensorflow】连续输入+离散输入的神经网络模型训练代码离散输入的转化问题构造词典创建离散数据、转化字典索引、创建连续数据创建离散输入+连续输入模型训练输出全部代码-复制即用  查看本系列三种模型写法:  【tensorflow】连续输入的线性回归模型训练代码 ......
  • 基于SURF+Affine+Ransac+ICP算法的三维点云室内场景重建matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:2.算法涉及理论知识概要三维点云室内重建是计算机视觉领域的一个重要研究方向,它可以为现实世界中的建筑空间提供高精度的三维模型。在这个领域中,SURF+AFFINE+RANSAC+ICP算法是一种常用的方法。本文将对这些算法进行详细介绍,并探讨它们在......
  • 基于SURF+Affine+Ransac+ICP算法的三维点云室内场景重建matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:    2.算法涉及理论知识概要      三维点云室内重建是计算机视觉领域的一个重要研究方向,它可以为现实世界中的建筑空间提供高精度的三维模型。在这个领域中,SURF+AFFINE+RANSAC+ICP算法是一种常用的方法。本文将对这些算......
  • 【笔记】大一下数值分析碎碎念——插值
    \(\newcommand\op[1]{\operatorname{#1}}\)插值给定数据点\((x_i,y_i)\),要求找到函数满足\(f(x_i)=y_i\)。线性插值:全局信息维护,光滑性(求导),积分都不太好搞。但是原理简单。多项式?指数?变化快。三角函数?周期性。多项式插值Weierstrass逼近定理:设\(f\in\opC[a,b]\),则......
  • 高压(3000V)IXBH10N300HV、IXYN50N170CV1离散式超轻穿通型(XPT™)高电压IGBT器件
    IXBH10N300HV是一款3000V高压反向导通(BiMOSFET™)IGBT器件,它将MOSFET和IGBT的优势相结合。这些高压器件的饱和电压和内置二极管的正向电压降均具有正电压温度系数,因此非常适合用于并联运行。“自由”内置体二极管用作保护二极管,为器件关断期间的感性负载电流提供替代路径,防止......
  • 应用案例分享 | 基于高精度三维机器视觉的汽车轮胎装配系统应用
    Part.1 行业背景汽车轮胎装配是汽车制造和维修过程中的关键环节,随着汽车产量的增加和市场竞争的加剧,汽车制造商对轮胎装配的自动化需求也越来越高。如今,汽车制造商们也正努力积极的提升其工艺技术水平,以应对不断增长的市场需求,希望采用更先进、更灵活、更智能的装配技术来提高汽车......
  • 恒压供水仿真/1200plc/博途v15可直接仿真运行,包含离散被控对象,手动干扰,随机干扰,pid参
    恒压供水仿真/1200plc/博途v15可直接仿真运行,包含离散被控对象,手动干扰,随机干扰,pid参数可调。ID:6966596086480080......
  • 基于高精度三维机器视觉的汽车曲轴无序抓取系统应用
    Part.1 行业背景汽车产业的高速发展,对零部件自动化生产提出了更高要求。随着汽车销量的水涨船高,传统的手工生产模式已经难以满足大批量生产的需求,自动化生产是必然趋势。曲轴是汽车发动机的关键组件之一,生产过程复杂,自动化生成相对较低。曲轴起到将往复运动转化为旋转运动的作用,通......
  • 论文解读|基于RealSense的三维散乱部件点云分割
    原创|文BFT机器人01摘要本文提出了一种针对垃圾拾取系统中点云分割的算法。该算法使用低成本的深度相机RealSense获取点云数据,并对点云数据进行滤波处理和分割,最终将分割后的子块片段独立地连接起来,形成完整的工件模型。通过测试案例验证了该算法的有效性和实用性。图1工作台上......
  • 呼叫中心的离散事件模拟(C++_模拟)
    题目       模拟网上书店的电话接待台接电话(离散事件)的过程。用户在打电话咨询时,先输入自己的标识(如姓名或会员号),然后进入排队等待被接听电话。xauat服务人员会根据该用户在书店已购买书籍的累计消费情况对拨入的电话进行排序。累计消费超过3000元的为1类用户,最先得......