PCL从理解到应用【03】KDTree 原理分析 | 案例分析 | 代码实现

前言

本文分析KDTree的原理,集合案例深入理解,同时提供源代码。

三个案例:K近邻搜索、半径内近邻搜索、近似最近邻搜索。方法对比,如下表所示:

特性K近邻搜索半径内近邻搜索近似最近邻搜索
描述查找K个最近邻点查找指定半径内的所有点查找近似最近邻点
返回结果数量固定K个不固定,取决于半径内点的数量不固定,取决于近似效果
适用场景需要固定数量最近邻点的应用需要查找固定范围内点的应用需要快速查询的应用
精度
速度较慢(点云数据量大时)较慢(半径大时)
代码复杂度

看一下示例效果:

白色的是随机生成的原始点云,红色是查询点,绿色是找到的10个最近点。

一、KDTree 原理分析

KDTree(K-Dimensional Tree,K维树)是一种用于多维空间中数据点的快速点查找的数据结构。它是计算几何领域中的一种二叉树。 

  • 构建过程:

    • 将数据点递归地划分成两个子集,直到每个子集中的点数目小于等于一个。
    • 每次划分时,选择某个维度,将数据点按照该维度的中位数进行分割,这样一半的数据点在分割超平面的左侧,另一半在右侧。
    • 每个节点保存一个数据点及一个用于分割的维度。
  • 搜索过程:

    • 从根节点开始,递归地向下遍历树,根据查询点在当前分割维度上的值决定向左子树或右子树移动,直到达到叶节点。
    • 回溯过程中,检查是否需要跨越分割超平面搜索另一子树。
    • 使用一个优先级队列维护当前最优的 K 个最近邻点。

二、KDTree常用方法

KDTree常用的方法,汇总如下所示:

1. setInputCloud 方法
void setInputCloud(const PointCloudConstPtr &cloud, const IndicesConstPtr &indices = IndicesConstPtr())
设置输入点云数据。

2. nearestKSearch 方法
int nearestKSearch(const PointT &point, int k, std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
查找查询点的K近邻。

3. radiusSearch 方法
int radiusSearch(const PointT &point, double radius, std::vector<int> &k_indices, std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const
查找查询点在指定半径内的所有近邻。

4. getPointCloud 方法
const PointCloudConstPtr& getPointCloud() const
获取输入点云。

5. getIndices 方法
const IndicesConstPtr& getIndices() const
获取索引。

6. approxNearestSearch 方法
int approxNearestSearch(const PointT &point, int &index, float &sqr_distance) const
查找查询点的近似最近邻。近似最近邻搜索相对于精确最近邻搜索速度更快,但结果不是完全准确的。

官网:Introduction — Point Cloud Library 0.0 documentation

对应函数:Point Cloud Library (PCL): Module kdtree

  • Point Cloud Library (PCL): pcl::KdTree< PointT > Class Template Reference

三、KDTree优缺点分析

优点:

  • 高效邻近搜索: 在低维数据中,KDTree 提供了一种高效的 K 近邻和范围搜索方法。
  • 动态更新: KDTree 可以动态地插入和删除数据点,保持数据结构的有效性。
  • 适用多种距离度量: KDTree 可以使用多种距离度量,如欧氏距离、曼哈顿距离等,适应不同应用需求。

缺点:

  • 高维数据性能下降: 随着维度增加,KDTree 的性能会急剧下降,这是因为高维空间中的数据分布变得稀疏,导致分割效率降低。这种现象被称为“维度灾难”。
  • 构建和维护成本: 构建和维护 KDTree 的成本较高,尤其是在数据频繁变化的场景中。
  • 不适用于动态变化的场景: 如果数据频繁更新,KDTree 需要频繁重建,维护成本较高。

四、KDTree案例——K近邻搜索

K近邻搜索(K-Nearest Neighbors Search)是一种用于查找给定点的K个最近邻点的搜索方法,KDTree提供了一种高效的实现方式。

看一个示例深入理解,在这个示例中:

  1. 随机生成一个包含1000个点的点云。
  2. 随机选择一个查询点。
  3. 使用 kdtree.nearestKSearch 进行近似最近邻搜索,查找10个距离最近的点。
  4. 使用 pcl::visualization::PCLVisualizer 可视化原始点云、查询点和近似最近邻点。

代码示例:

#include <pcl/point_cloud.h>        // 点类型定义头文件
#include <pcl/kdtree/kdtree_flann.h> // kdtree类定义头文件
#include <pcl/visualization/pcl_visualizer.h> // PCL可视化类定义头文件

#include <iostream>
#include <vector>
#include <ctime>
#include <chrono>
#include <thread>

/*
函数功能:
K近邻搜索 (K-Nearest Neighbors, KNN):找到距离查询点最近的K个点。
*/

int main (int argc, char** argv)
{
  srand(time(NULL)); // 用系统时间初始化随机种子

  // 创建一个PointCloud<pcl::PointXYZ>对象
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

  // 随机点云生成
  cloud->width = 1000;  // 点云数量
  cloud->height = 1;    // 表示点云为无序点云
  cloud->points.resize(cloud->width * cloud->height);

  for (size_t i = 0; i < cloud->points.size(); ++i) // 循环填充点云数据
  {
    cloud->points[i].x = 1024.0f * rand() / (RAND_MAX + 1.0f); // 产生数值为0-1024的浮点数
    cloud->points[i].y = 1024.0f * rand() / (RAND_MAX + 1.0f);
    cloud->points[i].z = 1024.0f * rand() / (RAND_MAX + 1.0f);
  }

  // 创建KdTreeFLANN对象,并把创建的点云设置为输入
  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
  kdtree.setInputCloud(cloud);

  // 设置查询点并赋随机值
  pcl::PointXYZ searchPoint;
  searchPoint.x = 1024.0f * rand() / (RAND_MAX + 1.0f);
  searchPoint.y = 1024.0f * rand() / (RAND_MAX + 1.0f);
  searchPoint.z = 1024.0f * rand() / (RAND_MAX + 1.0f);

  // K近邻搜索
  int K = 10; // 设置K值为10,表示查找10个最近邻
  std::vector<int> pointIdxNKNSearch(K);         // 存储查询点近邻的索引
  std::vector<float> pointNKNSquaredDistance(K); // 存储近邻点对应的距离平方

  // 打印相关信息
  std::cout << "K近邻搜索,查询点为 (" << searchPoint.x 
            << " " << searchPoint.y 
            << " " << searchPoint.z
            << "),K=" << K << std::endl;

  // 执行K近邻搜索
  if (kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
  {
    // 打印所有近邻坐标
    for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i)
      std::cout << "    " << cloud->points[pointIdxNKNSearch[i]].x 
                << " " << cloud->points[pointIdxNKNSearch[i]].y 
                << " " << cloud->points[pointIdxNKNSearch[i]].z 
                << " (距离平方: " << pointNKNSquaredDistance[i] << ")" << std::endl;
  }

  // 创建PCLVisualizer对象
  pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("nearestKSearch"));
  viewer->setBackgroundColor(0, 0, 0); // 设置背景色为黑色

  // 添加原始点云
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> originalColor(cloud, 255, 255, 255); // 白色
  viewer->addPointCloud<pcl::PointXYZ>(cloud, originalColor, "original cloud");

  // 添加查询点
  pcl::PointCloud<pcl::PointXYZ>::Ptr searchPointCloud(new pcl::PointCloud<pcl::PointXYZ>());
  searchPointCloud->push_back(searchPoint);
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> searchPointColor(searchPointCloud, 255, 0, 0); // 红色
  viewer->addPointCloud<pcl::PointXYZ>(searchPointCloud, searchPointColor, "search point");
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "search point");

  // 添加K近邻点
  pcl::PointCloud<pcl::PointXYZ>::Ptr kNearestPoints(new pcl::PointCloud<pcl::PointXYZ>());
  for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i)
  {
    kNearestPoints->push_back(cloud->points[pointIdxNKNSearch[i]]);
  }
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> kNearestColor(kNearestPoints, 0, 255, 0); // 绿色
  viewer->addPointCloud<pcl::PointXYZ>(kNearestPoints, kNearestColor, "k nearest points");
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "k nearest points");

  // 启动可视化
  viewer->addCoordinateSystem(1.0);
  viewer->initCameraParameters();
  while (!viewer->wasStopped())
  {
    viewer->spinOnce(100);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  return 0;
}

可视化K近邻搜索的效果,如下图所示:

白色的是随机生成的原始点云,红色是查询点,绿色是找到的10个最近点。

K近邻搜索的思路流程:

  • 初始化
    • 从根节点开始,根据查询点的坐标,决定向左子树还是右子树移动。
  • 递归搜索
    • 递归地向下遍历树,直至达到叶节点。
    • 在叶节点处,计算该叶节点数据点与查询点之间的距离,将其加入优先级队列(最大堆),用于存储当前最近的K个点。
  • 回溯
    • 回溯到父节点,检查当前节点的数据点与查询点之间的距离,并更新优先级队列。
    • 判断是否需要跨越分割超平面搜索另一子树:如果查询点到分割超平面的距离小于优先级队列中最远点的距离,则跨越分割超平面,进入另一子树进行搜索。
  • 重复搜索和回溯
    • 重复上述搜索和回溯过程,直至回溯到根节点,最终优先级队列中存储的就是查询点的K个最近邻点。
         构建KDTree
           /    \
          /      \
         /        \
       节点      节点
       /  \      /  \
      /    \    /    \
  节点    节点  节点  节点

五、KDTree案例——近似最近邻搜索搜索

近似最近邻搜索的目标是找到查询点的近似K个最近邻点,允许一定的误差以提高搜索速度。

常见的做法是通过多次随机采样、设置较大的搜索半径或者在其他库中使用误差参数来实现近似搜索。

特点K近邻搜索近似最近邻搜索
精度中等
性能速度较慢,计算量大速度快,计算量小
应用场景需要精确结果的场景,如分类、回归等允许一定误差的快速检索,如大规模数据处理、实时应用等
优点结果精确,找到的是最邻近的K个点搜索速度快,适用于大规模数据集
缺点在高维数据中性能急剧下降,计算量大结果不够精确,存在一定误差

示例代码:

#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <iostream>
#include <vector>
#include <ctime>
#include <algorithm>
#include <chrono>
#include <thread>

int main (int argc, char** argv)
{
  srand(time(NULL));

  // 创建一个PointCloud<pcl::PointXYZ>对象
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  cloud->width = 1000;
  cloud->height = 1;
  cloud->points.resize(cloud->width * cloud->height);

  for (size_t i = 0; i < cloud->points.size(); ++i)
  {
    cloud->points[i].x = 1024.0f * rand() / (RAND_MAX + 1.0f);
    cloud->points[i].y = 1024.0f * rand() / (RAND_MAX + 1.0f);
    cloud->points[i].z = 1024.0f * rand() / (RAND_MAX + 1.0f);
  }

  // 创建KdTreeFLANN对象,并把创建的点云设置为输入
  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
  kdtree.setInputCloud(cloud);

  // 设置查询点并赋随机值
  pcl::PointXYZ searchPoint;
  searchPoint.x = 1024.0f * rand() / (RAND_MAX + 1.0f);
  searchPoint.y = 1024.0f * rand() / (RAND_MAX + 1.0f);
  searchPoint.z = 1024.0f * rand() / (RAND_MAX + 1.0f);

  // 近似最近邻搜索
  int K = 10;
  int trials = 5; // 设置尝试次数,通过增加随机性来实现近似搜索
  std::vector<int> pointIdxNKNSearch(K);
  std::vector<float> pointNKNSquaredDistance(K);

  std::vector<int> all_neighbors;
  std::vector<float> all_distances;

  // 多次随机采样
  for (int t = 0; t < trials; ++t)
  {
    pcl::PointXYZ randomSearchPoint = searchPoint;
    randomSearchPoint.x += static_cast<float>(rand()) / RAND_MAX * 2.0 - 1.0;
    randomSearchPoint.y += static_cast<float>(rand()) / RAND_MAX * 2.0 - 1.0;
    randomSearchPoint.z += static_cast<float>(rand()) / RAND_MAX * 2.0 - 1.0;

    if (kdtree.nearestKSearch(randomSearchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
    {
      all_neighbors.insert(all_neighbors.end(), pointIdxNKNSearch.begin(), pointIdxNKNSearch.end());
      all_distances.insert(all_distances.end(), pointNKNSquaredDistance.begin(), pointNKNSquaredDistance.end());
    }
  }

  // 排序并去重
  std::vector<std::pair<float, int>> distance_index_pairs;
  for (size_t i = 0; i < all_neighbors.size(); ++i)
  {
    distance_index_pairs.emplace_back(all_distances[i], all_neighbors[i]);
  }

  std::sort(distance_index_pairs.begin(), distance_index_pairs.end());
  distance_index_pairs.erase(std::unique(distance_index_pairs.begin(), distance_index_pairs.end()), distance_index_pairs.end());

  // 选择前K个近似最近邻
  std::vector<int> final_neighbors;
  for (size_t i = 0; i < std::min(size_t(K), distance_index_pairs.size()); ++i)
  {
    final_neighbors.push_back(distance_index_pairs[i].second);
  }

  // 创建PCLVisualizer对象
  pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Vis"));
  viewer->setBackgroundColor(0, 0, 0); // 设置背景色为黑色

  // 添加原始点云
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> originalColor(cloud, 255, 255, 255); // 白色
  viewer->addPointCloud<pcl::PointXYZ>(cloud, originalColor, "original cloud");

  // 添加查询点
  pcl::PointCloud<pcl::PointXYZ>::Ptr searchPointCloud(new pcl::PointCloud<pcl::PointXYZ>());
  searchPointCloud->push_back(searchPoint);
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> searchPointColor(searchPointCloud, 255, 0, 0); // 红色
  viewer->addPointCloud<pcl::PointXYZ>(searchPointCloud, searchPointColor, "search point");
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "search point");

  // 添加近似最近邻点
  pcl::PointCloud<pcl::PointXYZ>::Ptr approxNearestPoints(new pcl::PointCloud<pcl::PointXYZ>());
  for (size_t i = 0; i < final_neighbors.size(); ++i)
  {
    approxNearestPoints->push_back(cloud->points[final_neighbors[i]]);
  }
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> approxNearestColor(approxNearestPoints, 0, 255, 0); // 绿色
  viewer->addPointCloud<pcl::PointXYZ>(approxNearestPoints, approxNearestColor, "approx nearest points");
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "approx nearest points");

  // 启动可视化
  viewer->addCoordinateSystem(1.0);
  viewer->initCameraParameters();
  while (!viewer->wasStopped())
  {
    viewer->spinOnce(100);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  return 0;
}

结果可视化:

结果分析:

  • 白色的是随机生成的原始点云,红色是查询点,绿色是找到的2个最近点(本文需要找到10个点的)。
  • 允许一定误差,以提高搜索速度。
  • 在示例代码中,通过增加随机性和多次采样来实现近似搜索,最终合并和去重结果。

六、KDTree案例——半径内近邻搜索

径内近邻搜索 (Radius Search),找到指定半径内的所有点。

思路流程:

  1. 构建 KDTree:首先,构建包含所有数据点的KDTree。这一步骤将数据点按空间位置递归地分割成子区域。
  2. 查询节点搜索:从根节点开始,检查当前节点是否在查询点的半径内。如果是,则将其加入结果集中。
  3. 递归搜索:递归地检查当前节点的子节点:
    • 如果查询球体与子节点对应的空间区域相交,则继续搜索该子节点。
    • 如果查询球体与子节点对应的空间区域不相交,则跳过该子节点。
  4. 合并结果:合并所有符合条件的节点,得到最终的近邻点集合。

看一个示例深入理解,在这个示例中:

  1. 随机生成一个包含1000个点的点云。
  2. 随机选择一个查询点。
  3. 使用 kdtree.radiusSearch 进行半径内近邻搜索,半径为116。
  4. 使用 pcl::visualization::PCLVisualizer 可视化原始点云、查询点和近似最近邻点。

代码示例:

#include <pcl/point_cloud.h>        // 点类型定义头文件
#include <pcl/kdtree/kdtree_flann.h> // kdtree类定义头文件
#include <pcl/visualization/pcl_visualizer.h> // PCL可视化类定义头文件

#include <iostream>
#include <vector>
#include <ctime>
#include <chrono>
#include <thread>

/*
函数功能:
半径内近邻搜索 (Radius Search):找到指定半径内的所有点。
*/
int main (int argc, char** argv)
{
  srand(time(NULL)); // 用系统时间初始化随机种子

  // 创建一个PointCloud<pcl::PointXYZ>对象
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

  // 随机点云生成
  cloud->width = 1000;  // 点云数量
  cloud->height = 1;    // 表示点云为无序点云
  cloud->points.resize(cloud->width * cloud->height);

  for (size_t i = 0; i < cloud->points.size(); ++i) // 循环填充点云数据
  {
    cloud->points[i].x = 1024.0f * rand() / (RAND_MAX + 1.0f); // 产生数值为0-1024的浮点数
    cloud->points[i].y = 1024.0f * rand() / (RAND_MAX + 1.0f);
    cloud->points[i].z = 1024.0f * rand() / (RAND_MAX + 1.0f);
  }

  // 创建KdTreeFLANN对象,并把创建的点云设置为输入
  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
  kdtree.setInputCloud(cloud);

  // 设置查询点并赋随机值
  pcl::PointXYZ searchPoint;
  searchPoint.x = 1024.0f * rand() / (RAND_MAX + 1.0f);
  searchPoint.y = 1024.0f * rand() / (RAND_MAX + 1.0f);
  searchPoint.z = 1024.0f * rand() / (RAND_MAX + 1.0f);

  // 半径内近邻搜索方法
  std::vector<int> pointIdxRadiusSearch;           // 存储近邻索引
  std::vector<float> pointRadiusSquaredDistance;   // 存储近邻对应距离的平方

  float radius = 256.0f * rand() / (RAND_MAX + 1.0f); // 随机生成某一半径

  // 打印输出
  std::cout << "半径内近邻搜索,查询点为 (" << searchPoint.x 
            << " " << searchPoint.y 
            << " " << searchPoint.z
            << "),半径=" << radius << std::endl;

  // 执行半径内近邻搜索方法
  if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)
  {
    // 打印所有近邻坐标
    for (size_t i = 0; i < pointIdxRadiusSearch.size(); ++i)
      std::cout << "    " << cloud->points[pointIdxRadiusSearch[i]].x 
                << " " << cloud->points[pointIdxRadiusSearch[i]].y 
                << " " << cloud->points[pointIdxRadiusSearch[i]].z 
                << " (距离平方: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
  }

  // 创建PCLVisualizer对象
  pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("radiusSearch"));
  viewer->setBackgroundColor(0, 0, 0); // 设置背景色为黑色

  // 添加原始点云
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> originalColor(cloud, 255, 255, 255); // 白色
  viewer->addPointCloud<pcl::PointXYZ>(cloud, originalColor, "original cloud");

  // 添加查询点
  pcl::PointCloud<pcl::PointXYZ>::Ptr searchPointCloud(new pcl::PointCloud<pcl::PointXYZ>());
  searchPointCloud->push_back(searchPoint);
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> searchPointColor(searchPointCloud, 255, 0, 0); // 红色
  viewer->addPointCloud<pcl::PointXYZ>(searchPointCloud, searchPointColor, "search point");
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "search point");

  // 添加半径内近邻点
  pcl::PointCloud<pcl::PointXYZ>::Ptr radiusNearestPoints(new pcl::PointCloud<pcl::PointXYZ>());
  for (size_t i = 0; i < pointIdxRadiusSearch.size(); ++i)
  {
    radiusNearestPoints->push_back(cloud->points[pointIdxRadiusSearch[i]]);
  }
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> radiusNearestColor(radiusNearestPoints, 0, 255, 0); // 绿色
  viewer->addPointCloud<pcl::PointXYZ>(radiusNearestPoints, radiusNearestColor, "radius nearest points");
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "radius nearest points");

  // 启动可视化
  viewer->addCoordinateSystem(1.0);
  viewer->initCameraParameters();
  while (!viewer->wasStopped())
  {
    viewer->spinOnce(100);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  return 0;
}

可视化半径内近邻搜索的效果,如下图所示:

白色的是随机生成的原始点云,红色是查询点,绿色是找到的3个最近点(半径范围内)。

半径内近邻搜索,查询点为 (200.242 73.3622 785.961),半径=116.108
    166.217 33.6048 783.911 (距离平方: 2742.57)
    164.154 125.101 776.535 (距离平方: 4068.13)
    239.646 7.50222 856.443 (距离平方: 10857.9)

分享完成~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统(CentOS)安装Mysql5.7.x

安装准备&#xff1a; Linux系统(CentOS)添加防火墙、iptables的安装和配置 请访问地址&#xff1a;https://blog.csdn.net/esqabc/article/details/140209894 1&#xff0c;下载mysql安装文件&#xff08;mysql-5.7.44为例&#xff09; 选择Linux通用版本64位&#xff08;L…

[深度学习]卷积理解

单通道卷积 看这个的可视化就很好理解了 https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md 多通道卷积 当输入有多个通道时,卷积核需要拥有相同的通道数. 假设输入有c个通道,那么卷积核的每个通道分别于相应的输入数据通道进行卷积,然后将得到的特征图对…

说明本文档目录是软件开发梳理需求常见问题QA文档,方便客户看,也方便我们的售前人员,需求分析人员,ui设计师,原型绘图人员,思维导图绘图人员查看。

https://doc.youyacao.com/117/2150 说明 本文档目录是软件开发梳理需求常见问题QA文档&#xff0c;方便客户看&#xff0c;也方便我们的售前人员&#xff0c;需求分析人员&#xff0c;ui设计师&#xff0c;原型绘图人员&#xff0c;思维导图绘图人员查看。 提示 本内容客户…

【ABB】控制器语言切换

【ABB】控制器语言切换 操作流程演示 操作流程 点击【菜单】点击【Control Panel】点击【Language】点击【Chinese】点击【OK】此时会弹出弹窗&#xff0c;点击【YES】此时控制器会重启&#xff0c;重启完成就是中文了 演示 点击【菜单】 点击【Control Panel】 点击【Langua…

4.2 投影

一、投影和投影矩阵 我们以下面两个问题开始&#xff0c;问题一是为了展示投影是很容易视觉化的&#xff0c;问题二是关于 “投影矩阵”&#xff08;projection matrices&#xff09;—— 对称矩阵且 P 2 P P^2P P2P。 b \boldsymbol b b 的投影是 P b P\boldsymbol b Pb。…

涂山璟无缘奥运会

“涂山璟无缘奥运会”在那片被浪漫与幻想包裹的剧集世界里&#xff0c;涂山璟与小夭的故事&#xff0c;如同夏日里的一缕清风&#xff0c;温柔而又坚定。当爱情以纯粹的形式展现&#xff0c;一个简单的愿望——亲手摘取湖中的海棠花&#xff0c;便成为了两人情感交流的甜蜜桥梁…

吉洪诺夫正则化随笔

前言 前几天在回顾压缩感知中的特征选择与LASSO回归发现了这个Tikhonov regularization&#xff0c;查了一下叫个如题的名字。先来浅说一下正则化这玩意&#xff1a;正则化&#xff08;Regularization&#xff09;是一种用来防止模型过拟合&#xff08;Overfitting&#xff09…

【数据库了解与学习】

1.下载所需版本安装包 1.1将所需文件压缩包以及安装包放在你选择的任意一盘&#xff0c;新建一个没有文字和空格的文件夹 1.2双击打开安装包&#xff0c;选择Custom自定义模式然后点击右下方的Next 1.4三连点击1&#xff0c;再点击箭头出现3&#xff0c;选中3出现4&#xff0c;…

AJAX-day1:

注&#xff1a;文件布局&#xff1a; 一、AJAX的概念&#xff1a; AJAX是浏览器与服务器进行数据通信的技术 >把数据变活 二、AJAX的使用&#xff1a; 使用axios库&#xff0c;与服务器进行数据通信 基于XMLHttpRequest封装&#xff0c;代码简单 Vue,React项目使用 学习…

day04-matplotlib入门

matplotlib Matplotlib 提供了一个套面向绘图对象编程的 API接口 是一款用于数据可视化的 Python 软件包&#xff0c;支持跨平台运行 它能够根据 NumPyndarray 数组来绘制 2D(3D) 图像&#xff0c;它使用简单、代码清晰易懂&#xff0c;深受广大技术爱好 者喜爱。 实列&…

云计算渲染时代:选择Blender或KeyShot进行高效渲染

在云渲染技术日益成熟的背景下&#xff0c;挑选一款贴合项目需求的3D渲染软件显得尤为关键。当前&#xff0c;Blender与KeyShot作为业界领先的全能渲染解决方案&#xff0c;广受推崇。它们虽皆能创造出令人信服的逼真视觉效果&#xff0c;但在特色功能上各有所长。本篇文章旨在…

加装德国进口高精度主轴 智能手机壳「高质量高效率」钻孔铣槽

在当前高度智能化的社会背景下&#xff0c;智能手机早已成为人们生活、工作的必备品&#xff0c;智能手机壳作市场需求量巨大。智能手机壳的加工过程涉及多个环节&#xff0c;包括钻孔和铣槽等。钻孔要求精度高、孔位准确&#xff0c;而铣槽则需要保证槽位规整、深度适宜。这些…

利用C语言实现三子棋游戏

文章目录 1.游戏界面2.游戏内容2.1 棋盘类型2.2棋盘的初始化2.3 打印棋盘的界面展示 3.游戏操作3.1 玩家操作3.2 电脑操作3.3 胜负判定 4.代码整合 1.游戏界面 无论写任何程序&#xff0c;我们都需要先去了解它的大概框架&#xff0c;这里我们先把它的初始界面写出来。一个游戏…

自动化设备上位机设计 二

目录 一 设计原型 二 后台代码 一 设计原型 二 后台代码 namespace 自动化上位机设计 {public partial class Form1 : Form{public Form1(){InitializeComponent();timer1.Enabled true;timer1.Tick Timer1_Tick;}private void Timer1_Tick(object? sender, EventArgs e)…

「媒体邀约」天津媒体资源?媒体邀约宣传报道

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 天津拥有丰富的媒体资源&#xff0c;利用这些资源进行有效…

数智化配补调:零售品牌增长新引擎

随着科技的不断进步和消费者需求的日益个性化、多元化&#xff0c;传统服装行业正面临着前所未有的挑战与机遇。在这个快速变化的时代&#xff0c;如何精准把握市场脉搏&#xff0c;实现库存的高效管理&#xff0c;成为了服装品牌生存与发展的关键。数智化配补调策略应运而生&a…

Java后端每日面试题(day3)

目录 Spring中Bean的作用域有哪些&#xff1f;Spring中Bean的生命周期Bean 是线程安全的吗&#xff1f;了解Spring Boot中的日志组件吗&#xff1f; Spring中Bean的作用域有哪些&#xff1f; Bean的作用域&#xff1a; singleton&#xff1a;单例&#xff0c;Spring中的bean默…

重载一元运算符

自增运算符 #include<iostream> using namespace std; class CGirl { public:string name;int ranking;CGirl() { name "zhongge"; ranking 5; }void show() const{ cout << "name : "<<name << " , ranking : " <…

卫星轨道平面简单认识

目录 一、轨道平面 1.1 轨道根数 1.2 应用考虑 二、分类 2.1 根据运行高度 2.2 根据运行轨迹偏心率 2.3 根据倾角大小 三、卫星星座中的轨道平面 四、设计轨道平面的考虑因素 一、轨道平面 1.1 轨道根数 轨道平面是定义卫星或其他天体绕行另一天体运动的平面。这个平…

小白 | Linux安装python3

一、更新包列表 首先&#xff0c;确保你的包管理器是最新的&#xff1a; sudo apt update 二、安装 Python 3 安装 Python 3 以及常用的开发工具 sudo apt install python3 python3-pip python3-venv 三、验证安装 python3 --version