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.mzph.cn/news/866799.shtml

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

相关文章

西安邀请媒体报道,附媒体名单

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 西安市&#xff0c;作为中国古都之一&#xff0c;不仅拥有…

Astro新前端框架首次体验

Astro新前端框架首次体验 1、什么是Astro Astro是一个静态网站生成器的前端框架&#xff0c;它提供了一种新的开发方式和更好的性能体验&#xff0c;帮助开发者更快速地构建现代化的网站和应用程序。 简单来说就是&#xff1a;Astro这个是一个网站生成器&#xff0c;可以直接…

DisFormer:提高视觉动态预测的准确性和泛化能力

最新的研究进展已经显示出目标中心的表示方法在视觉动态预测任务中可以显著提升预测精度&#xff0c;并且增加模型的可解释性。这种表示方法通过将视觉场景分解为独立的对象&#xff0c;有助于模型更好地理解和预测场景中的变化。 尽管在静态图像的解耦表示学习方面已经取得了一…

基于SpringBoot的乐校园二手书交易管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言 Java 数据库 MySQL 技术 SpringBoot框架 工具 Visual Studio、MySQL数据库开发工具 系统展示 首页 用户注册界面 二手图书界面 个人中心界面 摘要 乐校园…

go Channel原理 (四)

Channel 设计原理 不要通过共享内存的方式进行通信&#xff0c;而是应该通过通信的方式共享内存。 在主流编程语言中&#xff0c;多个线程传递数据的方式一般都是共享内存。 Go 可以使用共享内存加互斥锁进行通信&#xff0c;同时也提供了一种不同的并发模型&#xff0c;即通…

试用笔记之-VB微信支付支付宝支付源代码

首先下载VB微信支付&支付宝支付源代码 http://www.htsoft.com.cn/download/VB6WeiXin_ZhiFuBao_ZhiFu.rar

【一念发动便是行】念头,就是命运

一个个恶念累积就是负能量&#xff0c;念头就是命运&#xff0c;克除恶念&#xff0c;防范念头&#xff0c;念头都有能量&#xff0c;学圣学须内外庄严检肃&#xff0c;言语有灵 多数人的问题都是出在念头上&#xff0c;念头&#xff0c;就是自己的命运&#xff1b; 当我们对自…

Linux--信号(万字详解!超完整!)

目录 0.预备知识 0.1.基本概念 0.2.信号的捕捉 0.3.理解信号的发送与保存 1.信号的产生&#xff08;阶段一&#xff09; 1.通过kill命令&#xff0c;向指定进程发送指定的信号 2.通过终端按键产生信号&#xff1a;ctrlc&#xff08;信号2&#xff09;&#xff0c;ctrl\(…

【python】PyQt5控件尺寸大小位置,内容边距等API调用方法实战解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

第十二章 执行引擎

一、执行引擎概述 概述 执行引擎是 Java 虚拟机核心的组成部分之一。“虚拟机”是一个相对于“物理机”的概念&#xff0c;这两种机器都有代码执行能力&#xff0c;其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的&#xff0c;而虚拟机的执行引…

AlmaTech股份有限公司如何通过有效的营销本地化解锁全球市场

在当今全球化经济中&#xff0c;企业必须调整营销策略&#xff0c;以引起不同地区不同受众的共鸣。营销本地化&#xff0c;包括定制营销材料以满足各种市场的文化、语言和监管要求&#xff0c;对于实现这一目标至关重要。本案例研究探讨了领先的电子商务公司AlmaTech股份有限公…

解锁水利智慧:智慧水利的深度剖析与未来展望,探讨智慧水利如何助力水利行业实现数字化转型与智能化升级

本文关键词&#xff1a;智慧水利、智慧水利工程、智慧水利发展前景、智慧水利技术、智慧水利信息化系统、智慧水利解决方案、数字水利和智慧水利、数字水利工程、数字水利建设、数字水利概念、人水和协、智慧水库、智慧水库管理平台、智慧水库建设方案、智慧水库解决方案、智慧…

数据驱动下的SaaS渠道精细化运营:提升ROI的实战指南

在当今数字化转型的大潮中&#xff0c;SaaS&#xff08;Software as a Service&#xff09;企业面临着日益激烈的市场竞争。为了在市场中脱颖而出&#xff0c;实现可持续增长&#xff0c;SaaS企业必须转向更为精细化的运营模式&#xff0c;而数据驱动则是实现这一目标的关键。本…

TCP 的安全可靠

TCP的安全可靠 重传机制往返时间测量快速重传 流量控制拥塞控制 重传机制 T C P确认从另一端收到的数据以提供可靠的运输层&#xff0c;但数据和确认都有可能会丢失。 T C P通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认&#xff0c;它就重传该…

【C++】认识使用string类

【C】STL中的string类 C语言中的字符串标准库中的string类string类成员变量string类的常用接口说明成员函数string(constructor构造函数)~string(destructor析构函数)默认赋值运算符重载函数 遍历string下标[ ]迭代器范围for反向迭代器 capacitysizelengthmax_sizeresizecapaci…

不错的用户需求访谈方法

不错的用户需求访谈方法&#xff0c;可以用如下的矩阵&#xff0c;用来引导用户访谈&#xff1a;

【C++】哈希表 ---开散列版本的实现

你很自由 充满了无限可能 这是很棒的事 我衷心祈祷你可以相信自己 无悔地燃烧自己的人生 -- 东野圭吾 《解忧杂货店》 开散列版本的实现 1 前言2 开散列版本的实现2.1 节点设计2.2 框架搭建2.3 插入函数2.4 删除函数2.5 查找操作2.6 测试 Thanks♪(&#xff65;ω&#x…

python如何不保留小数

1、int() 向下取整&#xff08;内置函数&#xff09; n 3.75 print(int(n)) >>> 3 n 3.25 print(int(n)) >>> 3 2、round() 四舍五入&#xff08;内置函数&#xff09; n 3.75 print(round(n)) >>> 4 n 3.25 print(round(n)) >>> 3 …

SpringBoot实战:轻松实现XSS攻击防御(注解和过滤器)

文章目录 引言一、XSS攻击概述1.1 XSS攻击的定义1.2 XSS攻击的类型1.3 XSS攻击的攻击原理及示例 二、Spring Boot中的XSS防御手段2.1 使用注解进行XSS防御2.1.1 引入相关依赖2.1.2 使用XSS注解进行参数校验2.1.3 实现自定义注解处理器2.1.4 使用注解 2.2 使用过滤器进行XSS防御…