vtk中的点云曲面重建

2023-11-12

对于光学扫描设备(如激光雷达)采集到的非规则点云数据,最重要的需求之一就是进行表面重建(Surface Reconstruction):对成片密集分布的点云以三角片拟合,形成连续、精确、良态的曲面表示。
目前主流的算法可分为剖分类、组合类和拟合类。剖分类比如Voronoi图、Delaunay三角剖分,原始数据点即为顶点,数据无损失,数据冗余多,生成的曲面不光顺,容易受噪声影响。组合类比如 Power Crust、DBRG在剖分的基础上使用简单几何形状组合,使算法更稳定,并提供了拓扑信息。拟合类的算法以Hugues Hoppe提出的Signed Distance FunctionPoisson方法为代表。所得曲面并不完全与数据点重合,而是进行了一定的合并和简化,并对噪声有一定鲁棒性。
经典的Signed Distance Function重建算法主要流程如下:

  1. 对每个数据点,搜索其邻域数据点,使用特征向量方法计算法线和法平面
  2. 由于法线的方向可有正负两个不确定,故对全局使用最小生成树近似计算法线朝向
  3. 以立方体素(voxel)为单位,沿着曲面滑动延展,计算每个格顶点到法平面的距离
  4. 使用Marching Cube算法从立方体素中(插值地)提取三角面

VTK库提供的vtkSurfaceReconstructionFilter类实现了该算法。下面对其源码进行注释

int vtkSurfaceReconstructionFilter::RequestData(
  vtkInformation* vtkNotUsed( request ),
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  // 从pipeline中获取输入接口
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  vtkDataSet *input = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  // 从pipeline中获取输出接口
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  vtkImageData *output = vtkImageData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  const vtkIdType COUNT = input->GetNumberOfPoints();
  SurfacePoint *surfacePoints;
  surfacePoints = new SurfacePoint[COUNT];
  
  vtkIdType i, j;
  int k;

  // --------------------------------------------------------------------------
  // 1. Build local connectivity graph
  // -------------------------------------------------------------------------
  {
  //八叉树 用于邻域搜索
  vtkPointLocator *locator = vtkPointLocator::New();
  locator->SetDataSet(input);
  vtkIdList *locals = vtkIdList::New();
  // if a pair is close, add each one as a neighbor of the other
  for(i=0;i<COUNT;i++)
    {
    //遍历所有点
    SurfacePoint *p = &surfacePoints[i];
    vtkCopyBToA(p->loc,input->GetPoint(i));
    //查找当前点的邻域
    locator->FindClosestNPoints(this->NeighborhoodSize,p->loc,locals);
    int iNeighbor;
    for(j=0;j<locals->GetNumberOfIds();j++)
      {
      iNeighbor = locals->GetId(j);
      if(iNeighbor!=i)
        {
        //邻域有点  双向记录
        p->neighbors->InsertNextId(iNeighbor);
        surfacePoints[iNeighbor].neighbors->InsertNextId(i);
        }
      }
    }
  locator->Delete();
  locals->Delete();
  }

  // --------------------------------------------------------------------------
  // 2. Estimate a plane at each point using local points
  // --------------------------------------------------------------------------
  {
  double *pointi;
  double **covar,*v3d,*eigenvalues,**eigenvectors;
  covar = vtkSRMatrix(0,2,0,2);
  v3d = vtkSRVector(0,2);
  eigenvalues = vtkSRVector(0,2);
  eigenvectors = vtkSRMatrix(0,2,0,2);
  for(i=0;i<COUNT;i++)
    {
    SurfacePoint *p = &surfacePoints[i];

    // first find the centroid of the neighbors
    vtkCopyBToA(p->o,p->loc);
    int number=1;
    vtkIdType neighborIndex;
    //把所有点坐标加起来除以数量
    for(j=0;j<p->neighbors->GetNumberOfIds();j++)
      {
      neighborIndex = p->neighbors->GetId(j);
      pointi = input->GetPoint(neighborIndex);
      vtkAddBToA(p->o,pointi);
      number++;
      }
    vtkDivideBy(p->o,number);
    
    // then compute the covariance matrix
    //所有点坐标减中心点坐标 求协方差矩阵 加起来
    vtkSRMakeZero(covar,0,2,0,2);
    for(k=0;k<3;k++)
      v3d[k] = p->loc[k] - p->o[k];
    vtkSRAddOuterProduct(covar,v3d);
    for(j=0;j<p->neighbors->GetNumberOfIds();j++)
      {
      neighborIndex = p->neighbors->GetId(j);
      pointi = input->GetPoint(neighborIndex);
      for(k=0;k<3;k++)
        {
        v3d[k] = pointi[k] - p->o[k];
        }
      vtkSRAddOuterProduct(covar,v3d);
      }
    //除以数量
    vtkSRMultiply(covar,1.0/number,0,2,0,2);
    // then extract the third eigenvector
    vtkMath::Jacobi(covar,eigenvalues,eigenvectors);
    // third eigenvector (column 2, ordered by eigenvalue magnitude) is plane normal
    for(k=0;k<3;k++)
      {
      p->n[k] = eigenvectors[k][2];
      }
    }
  vtkSRFreeMatrix(covar,0,2,0,2);
  vtkSRFreeVector(v3d,0,2);
  vtkSRFreeVector(eigenvalues,0,2);
  vtkSRFreeMatrix(eigenvectors,0,2,0,2);
  }

  //--------------------------------------------------------------------------
  // 3a. Compute a cost between every pair of neighbors for the MST
  // 初步确定相邻点之间的法线关系  作为最小生成树的结点距离
  // --------------------------------------------------------------------------
  // cost = 1 - |normal1.normal2|
  // ie. cost is 0 if planes are parallel, 1 if orthogonal (least parallel)
  for(i=0;i<COUNT;i++)
    {
    SurfacePoint *p = &surfacePoints[i];
    p->costs = new double[p->neighbors->GetNumberOfIds()];

    // compute cost between all its neighbors
    // (bit inefficient to do this for every point, as cost is symmetric)
    for(j=0;j<p->neighbors->GetNumberOfIds();j++)
      {
      p->costs[j] = 1.0 -
        fabs(vtkMath::Dot(p->n,surfacePoints[p->neighbors->GetId(j)].n));
      }
    }

  // --------------------------------------------------------------------------
  // 3b. Ensure consistency in plane direction between neighbors
  // --------------------------------------------------------------------------
  // 确定法线朝向的问题与图的最大割问题等价,是NP难问题,因而不大可能求得精确解。使用最小生成树求法线的近似方向。从一点开始,贪心地找方向最接近的结点设为相同方向。
  // method: guess first one, then walk through tree along most-parallel
  // neighbors MST, flipping the new normal if inconsistent

  // to walk minimal spanning tree, keep record of vertices visited and list
  // of those near to any visited point but not themselves visited. Start
  // with just one vertex as visited.  Pick the vertex in the neighbors list
  // that has the lowest cost connection with a visited vertex. Record this
  // vertex as visited, add any new neighbors to the neighbors list.

    vtkIdList *nearby = vtkIdList::New(); // list of nearby, unvisited points

    // start with some vertex
    int first=0; // index of starting vertex
    surfacePoints[first].isVisited = 1;
    // add all the neighbors of the starting vertex into nearby
    for(j=0;j<surfacePoints[first].neighbors->GetNumberOfIds();j++)
      {
      nearby->InsertNextId(surfacePoints[first].neighbors->GetId(j));
      }

    double cost,lowestCost;
    int cheapestNearby = 0, connectedVisited = 0;

    //邻域待访问结点 repeat until nearby is empty
    while(nearby->GetNumberOfIds()>0)
      {
      // for each nearby point:
      vtkIdType iNearby,iNeighbor;
      lowestCost = VTK_DOUBLE_MAX;
      //对于每个未访问结点
      for(i=0;i<nearby->GetNumberOfIds();i++)
        {
        iNearby = nearby->GetId(i);
        // 遍历其邻域的每个已访问结点,计算方向的相似程度 找最小的
        for(j=0;j<surfacePoints[iNearby].neighbors->GetNumberOfIds();j++)
          {
          iNeighbor = surfacePoints[iNearby].neighbors->GetId(j);
          if(surfacePoints[iNeighbor].isVisited)
            {
            cost = surfacePoints[iNearby].costs[j];
            // pick lowest cost for this nearby point
            if(cost<lowestCost)
              {
              lowestCost = cost;
              cheapestNearby = iNearby;
              connectedVisited = iNeighbor;
              // 如果基本平行的话不用继续了 直接跳出
              if(lowestCost<0.1)
                {
                i = nearby->GetNumberOfIds();
                break;
                }
              }
            }
          }
        }
        //已访问结点=未访问结点 不可能的
      if(connectedVisited == cheapestNearby)
        {
        vtkErrorMacro (<< "Internal error in vtkSurfaceReconstructionFilter");
        return 0;
        }

      // 如果方向相反 就反向
      if(vtkMath::Dot(surfacePoints[cheapestNearby].n,
                      surfacePoints[connectedVisited].n)<0.0F)
        {
        // flip this normal
        vtkMultiplyBy(surfacePoints[cheapestNearby].n,-1);
        }
      // add this nearby point to visited
      surfacePoints[cheapestNearby].isVisited = 1;
      // remove from nearby
      nearby->DeleteId(cheapestNearby);
      // add all new nearby points to nearby 继续在该点的邻域搜索
      for(j=0;j<surfacePoints[cheapestNearby].neighbors->GetNumberOfIds();j++)
        {
        iNeighbor = surfacePoints[cheapestNearby].neighbors->GetId(j);
        if(surfacePoints[iNeighbor].isVisited == 0)
          {
          nearby->InsertUniqueId(iNeighbor);
          }
        }
      }

    nearby->Delete();

  // --------------------------------------------------------------------------
  // 4. Compute signed distance to surface for every point on a 3D grid
  // --------------------------------------------------------------------------
  {
  // 计算输出网格的长宽高、密度
  double bounds[6];
  for(i=0;i<3;i++)
    {
    bounds[i*2]=input->GetBounds()[i*2];
    bounds[i*2+1]=input->GetBounds()[i*2+1];
    }

  // estimate the spacing if required
  if(this->SampleSpacing<=0.0)
    {
    // spacing guessed as cube root of (volume divided by number of points)
    //体积除以点数 开立方根= 平均每个点的边长
    this->SampleSpacing = pow(static_cast<double>(bounds[1]-bounds[0])*
                              (bounds[3]-bounds[2])*(bounds[5]-bounds[4]) /
                              static_cast<double>(COUNT),
                              static_cast<double>(1.0/3.0));
    }

  // allow a border around the volume to allow sampling around the extremes
  for(i=0;i<3;i++)
    {
    bounds[i*2]-=this->SampleSpacing*2;
    bounds[i*2+1]+=this->SampleSpacing*2;
    }

  double topleft[3] = {bounds[0],bounds[2],bounds[4]};
  double bottomright[3] = {bounds[1],bounds[3],bounds[5]};
  int dim[3];
  for(i=0;i<3;i++)
    {
    dim[i] = static_cast<int>((bottomright[i]-topleft[i])/this->SampleSpacing);
    }

  // initialise the output volume
  //输出的是全部内容
  outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
               0, dim[0]-1, 0, dim[1]-1, 0, dim[2]-1);
  //输出的范围
  output->SetExtent(0, dim[0]-1, 0, dim[1]-1, 0, dim[2]-1);
  //原点坐标
  output->SetOrigin(bounds[0], bounds[2], bounds[4]); // these bounds take into account the extra border space introduced above
  //沿三个方向的坐标间距
  output->SetSpacing(this->SampleSpacing, this->SampleSpacing, this->SampleSpacing);
  //根据刚刚设置的参数分配存储空间 由outInfo确定数据类型和通道数
  output->AllocateScalars(outInfo);
  outInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
               0, dim[0]-1, 0, dim[1]-1, 0, dim[2]-1);

  vtkFloatArray *newScalars =
    vtkFloatArray::SafeDownCast(output->GetPointData()->GetScalars());
  outInfo->Set(vtkDataObject::SPACING(),
               this->SampleSpacing, this->SampleSpacing, this->SampleSpacing);
  outInfo->Set(vtkDataObject::ORIGIN(),topleft,3);

  // initialise the point locator (have to use point insertion because we need to set our own bounds, slightly larger than the dataset to allow for sampling around the edge)
  //邻域搜索器
  vtkPointLocator *locator = vtkPointLocator::New();
  vtkPoints *newPts = vtkPoints::New();
  //指定数据存储的位置和位置范围盒
  locator->InitPointInsertion(newPts,bounds,static_cast<int>(COUNT));
  for(i=0;i<COUNT;i++)
    {
    locator->InsertPoint(i,surfacePoints[i].loc);
    }

  // go through the array probing the values
  int x,y,z;
  int iClosestPoint;
  int zOffset,yOffset,offset;
  double probeValue;
  double point[3],temp[3];
  for(z=0;z<dim[2];z++)
    {
    zOffset = z*dim[1]*dim[0];
    point[2] = topleft[2] + z*this->SampleSpacing;
    for(y=0;y<dim[1];y++)
      {
      yOffset = y*dim[0] + zOffset;
      point[1] = topleft[1] + y*this->SampleSpacing;
      for(x=0;x<dim[0];x++)
        {
        point[0] = topleft[0] + x*this->SampleSpacing;
        // find the distance from the probe to the plane of the nearest point
        iClosestPoint = locator->FindClosestInsertedPoint(point);
        vtkCopyBToA(temp,point);
        //方格顶点坐标减去数据点坐标
        vtkSubtractBFromA(temp,surfacePoints[iClosestPoint].loc);
        //在法线上的投影长度 决定signed distance
        probeValue = vtkMath::Dot(temp,surfacePoints[iClosestPoint].n);
        offset = x + yOffset;      //点索引 
        newScalars->SetValue(offset,probeValue);
        }
      }
    }
  locator->Delete();
  newPts->Delete();
  }

  delete [] surfacePoints;

  return 1;
}

Hugues Hoppe在其1994年的博士论文中对于曲面的优化和保角简化还有一整套详细讨论。

vtkExtractSurface使用了类似的方法,并可以利用Range的可见性信息以确定法线方向。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vtk中的点云曲面重建 的相关文章

  • vtk数据交互的两种方式之回调函数、vtkCommand

    参考博客 VTK交互之vtkCommand 阿兵 AI医疗的博客 CSDN博客 vtkcommand 一 观察者 命令模式 VTK中用的较多的设计模式是 观察者 命令模式 Observer Command 要实现数据交互 主要基于观察者 命
  • Python VTK 球体贴图代码详解(二)

    效果 继昨天的柱体代码学习 之后尝试了一把球体并进行贴图 效果如下 代码 代码是在昨天柱体基础上修改成球体 并针对球体贴图多了两步 import vtk 柱体 生成一个球体 sphere vtk vtkSphereSource 半径 sph
  • VTK编译笔记

    VTK 是一个用于计算机图形学 可视化和图像处理的开源 面对对象软件系统 准备工具 编译 VTK 需要以下工具 括号内是本例中使用的版本 VTK 源码包 https vtk org download 本例下载的是 VTK 9 2 0 rc1
  • VTK相机类vtkCamera原理及用法

    vtk是著名的开源三维渲染库 在三维渲染过程中的一个非常重要的内容就是相机即vtkCamera类的设置 在VTK中 相机的实质是一个观测点 VTK的官方Doc对vtkCamera写的十分简略 暗坑很多 在学习和使用vtkCamera的过程中
  • 关于医学影像中的轴位面(横断面)、冠状面、矢状面

    冠状位矢状位轴位图解 第1页 概述 该页主题为冠状位矢状位轴位图解的图片集 内容包含有冠状位 矢状位 横断位具体怎么辨别 谢谢 ct 解剖 颞骨大体解剖 轴位及冠状位ct断层图像 解剖 颞骨大体解剖 轴位及冠状位ct断层图像 图1 a 矢状
  • vtk教程第三章 计算机图形学入门

    计算机图形学是数据可视化的基础 实际上 可视化是将数据转换为一组图形原语的过程 然后使用计算机图形学的方法将这些原语转换成图片或动画 本章讨论计算机图形学的基本原理 我们从描述光和物理物体如何相互作用形成我们所看到的开始 接下来 我们将研究
  • cmake+QT+VTK常见错误及解决方法

    1 安装环境 cmake3 0 QT4 8 6 VTK5 10 PS VTK6 10以上只能配合使用QT5 0以上版本 2 编译安装 参考 http blog csdn net www doling net article details
  • VTK(0)---CMake工程

    VTK 0 CMake工程 目录 前言 一 指定cmake版本 二 设置工程 三 针对Qt 自动使用moc uic rcc程序预处理 h文件 ui文件等 四 平台移植问题 五 设置编译模式 六 找到包 七 包含头文件等 八 链接库文件 九
  • 如何在vtk中以不同的颜色显示点云?

    我有一个点云 我想在 vtk 中可视化 我想根据某些条件看到它们具有不同的颜色 我正在使用Python 关于如何做到这一点有什么建议吗 多谢 下面是一个根据 z 轴值设置点颜色的示例 import vtk from numpy import
  • vtkStandardNewMacro 给出错误 C4430:缺少类型说明符

    我有以下代码 include
  • 如何获取 std::vector 中 vtkDoubleArray 的值

    我想复制 a 的元素vtkDoubleArray转换为 C std vector as in 如何将 vtkDoubleArray 转换为 Eigen matrix https stackoverflow com questions 246
  • 来自主线程的 VTK 窗口线程,C++

    我刚刚学习 VTK 和 C GUI 编程 希望有一个简单的问题 主应用程序在应用程序中的某个时刻启动渲染的窗口 希望在显示 VTK 窗口时主线程能够继续 是否有特定的方法可以将 VTK 窗口作为线程启动 我的环境是 Linux 可以使用 b
  • 使用 python3.8 和 Ubuntu 20.04 设置 VTK

    我最近将系统更新到 Ubuntu 20 04 我的 python 现在是 3 8 从此我的一切import vtk线路不行 ModuleNotFoundError No module named vtk 我努力了apt get python
  • vtkRenderer 错误

    我是 vtk 的新手 所以我首先使用 CMake 和 Visual Studio 2017 构建 vtk 8 1 1 并使用默认选项和示例 许多示例运行良好 但其中一些会出现错误 这是 CreateTree 示例 但 HelloWorld
  • 如何在一个 .vtu 文件中写入多个 vtkUnstructedGrid

    我想在一个 vtu 文件中写入多个非结构化网格 我在下面尝试过 MakeHexagonalPrism 和 MakeHexahedron 返回 vtkSmartPointer 类型 结果是输出文件中只有一个非结构化网格 vtkSmartPoi
  • CMakeExternalProject_Add() 和 FindPackage()

    是否有正确的方法来查找图书馆 通过FindPackage 是用ExternalProject Add 问题是 CMake 无法在 CMake 时找到该库 因为外部库是在编译时构建的 我知道在超级构建中构建库和项目时可以组合这两个 CMake
  • Mayavi (Python) 中的 TVTK 错误

    我正在运行 Fedora 17 x64 机器 并且我尝试通过以下方式安装 Mayavi for python yum install mayavi 工作得很好 除了每次我编写调用 mayavi 模块 如 mlab 的代码时 from ent
  • 有没有办法使用 Mayavi 填充陀螺仪表面的一侧?

    我正在使用 Mayavi 绘制陀螺仪的等值面 我的问题是我需要通过填充两个生成区域的一侧来获得更坚固的结构 在下面的图片中 您可以看到我生成的等值面的外观以及填充一侧后的外观 我生成的等值面 它应该是什么样子 等值面可以通过以下方程生成 U
  • 如何用VTK存储矢量场? C++、VTKWriter

    比方说 我有一个向量场 u 其分量为 ux uy 和 uz 定义在空间 rx ry 和 rz 中的 非结构化 位置 我想要的只是用 VTK 格式存储这个向量场 即使用 libvtk 中的 vtkwriter 类来存储 Paraview 的可
  • 在Python中从VTK文件中检索面和点

    我有一个包含 3d 模型的 vtk 文件 我想提取点坐标和面 这是一个最小的工作示例 import vtk import numpy from vtk util numpy support import vtk to numpy reade

随机推荐

  • 手写算法-python代码实现DBSCAN

    手写算法 python代码实现DBSCAN 原理解析 代码实现 实例演示与sklearn对比 总结 原理解析 上篇文章我们优化了Kmeans聚类算法 最后留下一个问题 Kmeans只适合处理凸样本集 不适合处理非凸样本集 这个问题 怎么解决
  • 2023最系统的网络安全学习路线

    什么是网络安全 网络安全是指保护计算机网络及其系统和应用程序的安全性和完整性 防止未经授权的访问 攻击 病毒 恶意软件和其他安全威胁 它是通过技术 管理和教育等综合手段来确保网络信息安全 网络安全包括网络防火墙 入侵检测系统 数据加密 网络
  • 【大模型】开源大模型汇总以及微调策略

    目录 前言 LLaMA stanford Alpaca Guanaco Vicuna Chinese LLaMA Alpaca Chinese Vicuna Luotuo Chinese Falcon OpenBuddy Falcon Ch
  • 数据结构第一章内容(思维导图以及概要)

    思维导图和内容概要 一 数据结构的基本概念 ps 与数据元素本身的形式 内容 相对位置 个数无关的是数据的逻辑结构 通常要求同一逻辑结构中的所有数据元素具有相同的特性 这意味着不仅数据元素所包含的数据项的个数要相同 而且对应数据项的类型要一
  • (一)python爬虫验证码识别(去除干扰线)

    一 python爬虫验证码识别 去除干扰线 1 开发环境与工具 python27 sklearn pytesser opencv等 pycharm windows7 2 数据集 用request库爬虫抓取某一网站验证码1200张 并做好标注
  • 满满的干货!java计算公式引擎

    Spring 全家桶 Spring 原理 Spring面试题 思维导图 面试题 Spring视频 Spring 原理 Spring特点 Spring 核心组件 Spring常用模块 Spring主要包 Spring常用注解 Sping第三方
  • MYSQL数据库锁常用sql(解决锁表,锁库)

    MYSQL数据库锁常用sql 解决锁表 锁库 查询数据库锁 SELECT FROM INFORMATION SCHEMA INNODB LOCKS 查看等待锁的事务 SELECT FROM INFORMATION SCHEMA INNODB
  • 谷歌整体战略:关于人工智能、云服务和登月计划的未来

    转载自我的博客 谷歌整体战略 关于人工智能 云服务和登月计划的未来 CB Insights 今日发布了一篇关于谷歌业务战略的深度分析报告 Google Strategy Teardown Betting The Future On AI C
  • qt自定义标题栏和边框_在Windows 7中自定义标题栏和其他系统字体

    qt自定义标题栏和边框 Would you like to tweak your title bar and menu fonts in Windows 7 Here s how you can change those little se
  • 嵌入式软件国际化(多语言) 点阵字库选择分析

    概述 嵌入式软件国际化 多语言 点阵字库选择分析 多字节字符集与unicode 多字节编码最大的问题在于每一个语种的字符集编码不兼容 unicode的好处在于将所有人类语种字符都有了统一的编码 现在世界上语言基本都包含在了基本多文种平面0上
  • c语言输出字符串显示在屏幕上,C语言输出printf

    C语言输出printf教程 在 在我们使用 printf 函数时 格式占位符的格式个数一定要与后面的需要输出的变量或者字面量的个数匹配 否则程序报错 printf函数详解 语法 int printf const char format 参数
  • Vue中动画的实现 从基本动画,到炫酷动画。看这一篇就够了

    文章目录 Vue中的基本动画实现 动画类名的重定义 使用第三方的动画库 我就选择其中一个库做示范其他都一样 Vue中的基本动画实现 直接一点 基本动画的步骤 在需要加动画的地方 加入transition
  • EXCEL实现多行多列转为一行多列形式,OFFSET函数

    1 需要实现数据多行多列转为一行多列的数据 2 使用函数 OFFSET A 1 COLUMN A1 1 3 MOD COLUMN A1 1 3 可根据实际数据情况替换数字 引用单元格 3 实现效果 4 操作步骤 观察数据 输入公式 点击回车
  • C++中的STL中(容器、迭代器、适配器、配置器)

    首先明确STL中的六大组成部分 容器 迭代器 适配器 算法 仿函数 配置器 一 C 中的容器 顺序容器 关联容器 容器适配器 1 顺序容器 2 关联容器 3 容器适配器 二 STL中 容器 适配器的关系 参考博客如下 C 顺序性容器 关联性
  • QT固定文件名格式串转化为TreeView在界面上展示文件树形目录

    获得的文件串格式 file1 1 sss txt file1 bin zip file2 linpanhu docx qmake vc bat send zip 思路 gt gt gt file1 1 sss txt file1 bin z
  • golang The system cannot find the file specified

    使用io ioutil包读取文件时报错 open abi The system cannot find the file specified 原因是 ioutil ReadFile 这个方法需要传入决绝路径的文件名 代码 abiStr er
  • ESP32 之 ESP-IDF 教学(十一)WiFi篇—— WiFi两种模式

    本文章 来自原创专栏 ESP32教学专栏 基于ESP IDF 讲解如何使用 ESP IDF 构建 ESP32 程序 发布文章并会持续为已发布文章添加新内容 每篇文章都经过了精打细磨 通过下方对话框进入专栏目录页 CSDN 请求进入目录 O
  • 安全模型和业务安全体系

    网络安全和业务安全 网络安全中 攻击者往往通过技术手段 以非正常的技术 XSS Injection Penestrating等 影响业务正常运行 窃取敏感数据 比如 某黑客通过SSRF进入内网 并在内网横向扩张 最终脱库成功 业务安全中 黑
  • 如何理解和解决CXXABI not found问题?

    编译C 程序时 在链接阶段有时会出现CXXABI not found的问题 usr lib64 libstdc so 6 version CXXABI 1 3 8 not found 问题出现的场景 当前编译的程序需要依赖其它已编译的组件
  • vtk中的点云曲面重建

    对于光学扫描设备 如激光雷达 采集到的非规则点云数据 最重要的需求之一就是进行表面重建 Surface Reconstruction 对成片密集分布的点云以三角片拟合 形成连续 精确 良态的曲面表示 目前主流的算法可分为剖分类 组合类和拟合