PCL点云库入门——PCL库点云特征之PFH点特征直方图(Point Feature Histograms -PHF)

1、算法原理

        PFH点(Point Feature Histogram)特征直方图的原理涉及利用参数化查询点与邻域点之间的空间差异,并构建一个多维直方图以捕捉点的k邻域几何属性。这个高维超空间为特征表示提供了一个可度量的信息空间,对于点云对应曲面的六维姿态,它具有不变性,并且在不同的采样密度或邻域噪声水平下表现出鲁棒性。PFH特征描述表示法基于点与其k邻域之间的关系以及它们的估计法线,简而言之,它考虑了所有估计法线方向之间的相互作用,试图捕捉最佳的样本表面变化情况,以描述样本的几何特征。因此,合成特征超空间依赖于每个点的表面法线估计质量。图1展示了查询点Pq的PFH计算影响区域,Pq以红色标记并置于圆球中心,半径为r,所有与Pq的距离小于半径r的k邻元素(即所有点)都相互连接在一个网络中。最终的PFH特征描述子是通过计算邻域内所有点对之间关系得到的直方图,公用有K*(K+1)/2个点对。

 图1 

        PFH特征描述实现的步骤如下:

        第1步:构建局部坐标系

        为了描述两点Ps和Pt及与它们对应的法线Ns和Nt之间的相对偏差,我们在其中一个点上定义一个固定的 Darboux标系,为了使该坐标架被唯一的确定,如图2所示。

图2 

        其中u,v,w具体如下:

        其中,Ps被定义为源点,Pt被定义为目标点。源点即Ps的选择是使得其关联的法线与连接两点的直线之间的角度最小。 

        第2步:特征描述

        在第1步中的vuw坐标系下,法线Ns和Nt之间的相对偏差可以用一组角度特征描述,定义为下:

        其中α和ϕ为单位向量的内积,取值范围为[-1,1],θ为角度,取值范围[-π/2,π/2];d为两点欧式距离,取值范围为(0,2r)。Pq点的PFH特征为α,θ,ϕ,d组成的四元特征。

        第3步:特征编码:

        为计算查询点Pq的PFH特征,根据点的四元特征(α,θ,ϕ,d)构建频率直方图,具体而言,先将<α,θ,ϕ,d>中的每个特征值范围划分为b个子区间(默认为5,可自行计算并设置),则4个特征共有b^4个区间,然后,统计对应特征值落在每个子区间的点的数目,由于<α,ϕ,θ>三个特征都是法线之间的角度息,则它们可归为同一个空间,最后,计算每一个点对的特征值,直方图中对应于该点对四个特征值区间的统计个数加1,效果图3所示。

图3 

在实际工作中距离特征d通常跟设备捕获2.5D深度数据是相关的,临近点的距离d是从视点开始递增的,在不同视角下,这些值的变化意义不大,所以在扫描局部点密度影响特征时,省略距离d效果会更好。在PCL 点云库中 FPH 特征描述只用了三个角度特征,因而特征矢量是5^3=125 维,对应PCL中的pcl::PFHSignature125数据类型。内容如下:

  struct PFHSignature125{float histogram[125] = {0.f};static constexpr int descriptorSize () { return detail::traits::descriptorSize_v<PFHSignature125>; }inline PFHSignature125 () = default;friend std::ostream& operator << (std::ostream& os, const PFHSignature125& p);};

 2、主要成员函数和变量

        1、主要成员变量

         1)、每个角度特征区间的划分数,默认为5。

    int nr_subdiv_;

          2)、点的PFH特征描述的占位符。

    Eigen::VectorXf pfh_histogram_;

          3)、PFH的4元特征的占位符。

    Eigen::Vector4f pfh_tuple_;

          4)、map数据类型,用于优化冗余计算的效率。

    std::map<std::pair<int, int>, Eigen::Vector4f, std::less<>,Eigen::aligned_allocator<std::pair<const std::pair<int, int>, Eigen::Vector4f> > > feature_map_;

        5)、中间计算结果保存的对队列。

     std::queue<std::pair<int, int> > key_list_;

       6)、设置最大内部缓存大小。

      unsigned int max_cache_size_;

       7)、设置为true表示使用缓存中间计算结果,减少冗余计算。

     bool use_cache_;

        2、主要成员函数

        1)、设置最大内部缓存大小。默认值为2GB。

 inline voidsetMaximumCacheSize (unsigned int cache_size);

        2)、设置是否使用内部缓存机制减少冗余计算。

inline voidsetUseInternalCache (bool use_cache);

        3)、计算点三个角度和两点之间的距离的4元特征。

 bool computePairFeatures (const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,int p_idx, int q_idx, float &f1, float &f2, float &f3, float &f4);

        4)、基于具有法线的三维点的空间邻域,估计给定点的三个角(f1, f2, f3)特征的PFH特征直方图。

    void computePointPFHSignature (const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,const std::vector<int> &indices, int nr_split, Eigen::VectorXf &pfh_histogram);

3、主要部分代码注解

        1、计算点对的四元特征

//1、计算点对的四元特征
//
template <typename PointInT, typename PointNT, typename PointOutT> bool
pcl::PFHEstimation<PointInT, PointNT, PointOutT>::computePairFeatures(const pcl::PointCloud<PointInT>& cloud, const pcl::PointCloud<PointNT>&  normals,int p_idx, int q_idx, float& f1, float& f2, float& f3, float& f4)
{pcl::computePairFeatures(cloud.points[p_idx].getVector4fMap(),  normals.points[p_idx].getNormalVector4fMap(),cloud.points[q_idx].getVector4fMap(),  normals.points[q_idx].getNormalVector4fMap(),f1, f2, f3, f4);return (true);
}
//算法具体实现,对应1中第2步的公式;
bool pcl::computePairFeatures(const Eigen::Vector4f& p1, const Eigen::Vector4f& n1,const Eigen::Vector4f& p2, const Eigen::Vector4f& n2,float& f1, float& f2, float& f3, float& f4)
{//距离特征dEigen::Vector4f dp2p1 = p2 - p1;dp2p1[3] = 0.0f;f4 = dp2p1.norm();if (f4 == 0.0f){PCL_DEBUG("[pcl::computePairFeatures] Euclidean distance between points  is 0!\n");f1 = f2 = f3 = f4 = 0.0f;return (false);}//计算ϕ角度特征Eigen::Vector4f n1_copy = n1,n2_copy = n2;n1_copy[3] = n2_copy[3] = 0.0f;float angle1 = n1_copy.dot(dp2p1) / f4;// 根据角度大小来选择源点Ps,选择角度最小的为Ps点,std::acos是递减函数float angle2 = n2_copy.dot(dp2p1) / f4;if (std::acos(std::fabs(angle1)) > std::acos(std::fabs(angle2))){// switch p1 and p2n1_copy = n2;n2_copy = n1;n1_copy[3] = n2_copy[3] = 0.0f;dp2p1 *= (-1);f3 = -angle2;}elsef3 = angle1;//创建 Darboux 坐标系 u-v-w// u = n1; v = (p_idx - q_idx) x u / || (p_idx - q_idx) x u ||; w = u x vEigen::Vector4f v = dp2p1.cross3(n1_copy);v[3] = 0.0f;float v_norm = v.norm();if (v_norm == 0.0f){PCL_DEBUG("[pcl::computePairFeatures] Norm of Delta x U is 0!\n");f1 = f2 = f3 = f4 = 0.0f;return (false);}// Normalize vv /= v_norm;Eigen::Vector4f w = n1_copy.cross3(v);// Do not have to normalize w - it is a unit vector by construction//计算θ精度特征v[3] = 0.0f;f2 = v.dot(n2_copy);w[3] = 0.0f;//计算α角度特征 4元特征(α,θ,ϕ,d)// Compute f1 = arctan (w * n2, u * n2) i.e. angle of n2 in the x=u, y=w  coordinate systemf1 = std::atan2(w.dot(n2_copy), n1_copy.dot(n2_copy)); // @todo optimize thisreturn (true);
}

        2、计算单点PFH特征信息

//2、计算单点PFH特征信息
//
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PFHEstimation<PointInT, PointNT, PointOutT>::computePointPFHSignature(const pcl::PointCloud<PointInT>& cloud, const pcl::PointCloud<PointNT>&  normals,const std::vector<int>& indices, int nr_split, Eigen::VectorXf& pfh_histogram)
{int h_index, h_p;//清楚上一次的PFH结果pfh_histogram.setZero();// 分解常数float hist_incr = 100.0f / static_cast<float> (indices.size() * (indices.size()  - 1) / 2);std::pair<int, int> key;bool key_found = false;// Iterate over all the points in the neighborhoodfor (std::size_t i_idx = 0; i_idx < indices.size(); ++i_idx){for (std::size_t j_idx = 0; j_idx < i_idx; ++j_idx){// 无序点检测,是则跳过if (!isFinite(cloud.points[indices[i_idx]]) ||  !isFinite(cloud.points[indices[j_idx]]))continue;//使用缓存来加速计算if (use_cache_){// 创建map需要的键值,为点云的索引int p1, p2;//      if (indices[i_idx] >= indices[j_idx])//      {p1 = indices[i_idx];p2 = indices[j_idx];//      }//      else//      {//        p1 = indices[j_idx];//        p2 = indices[i_idx];//      }key = std::pair<int, int>(p1, p2);// 检查是否已经在map中已经估计的点对,就不需要重新计算,避免重复计算std::map<std::pair<int, int>, Eigen::Vector4f,  std::less<>, Eigen::aligned_allocator<std::pair<const std::pair<int, int>,  Eigen::Vector4f> > >::iterator fm_it = feature_map_.find(key);if (fm_it != feature_map_.end()){//已经有计算的直接用计算的结果pfh_tuple_ = fm_it->second;key_found = true;}else{//没有被估计过,需要计算,这对新的点对的4元特征if (!computePairFeatures(cloud, normals,  indices[i_idx], indices[j_idx],pfh_tuple_[0], pfh_tuple_[1],  pfh_tuple_[2], pfh_tuple_[3]))continue;key_found = false;}}else//不使用缓存,直接计算所有两对点之间的4元特征if (!computePairFeatures(cloud, normals, indices[i_idx],  indices[j_idx],pfh_tuple_[0], pfh_tuple_[1], pfh_tuple_[2],  pfh_tuple_[3]))continue;// 将f1, f2, f3特征归一化,并将它们存储到直方图f_index_[0] = static_cast<int> (std::floor(nr_split *  ((pfh_tuple_[0] + M_PI) * d_pi_)));if (f_index_[0] < 0)         f_index_[0] = 0;if (f_index_[0] >= nr_split) f_index_[0] = nr_split - 1;f_index_[1] = static_cast<int> (std::floor(nr_split *  ((pfh_tuple_[1] + 1.0) * 0.5)));if (f_index_[1] < 0)         f_index_[1] = 0;if (f_index_[1] >= nr_split) f_index_[1] = nr_split - 1;f_index_[2] = static_cast<int> (std::floor(nr_split *  ((pfh_tuple_[2] + 1.0) * 0.5)));if (f_index_[2] < 0)         f_index_[2] = 0;if (f_index_[2] >= nr_split) f_index_[2] = nr_split - 1;// 特征直方图统计h_index = 0;h_p = 1;for (const int& d : f_index_){h_index += h_p * d;h_p *= nr_split;}//统计直方图结果pfh_histogram[h_index] += hist_incr;//缓存新计算点对的4元特征if (use_cache_ && !key_found){//保存4元特征信息到map中,根据Key由点的索引值feature_map_[key] = pfh_tuple_;// 将计算过的点对保存起来,为了防止冗余计算key_list_.push(key);// 如果缓存的量操过设置的最大值,需要清除最先缓存的值if (key_list_.size() > max_cache_size_){//删除最先缓存的元素。feature_map_.erase(key_list_.front());key_list_.pop();}}}}
}

        3、计算所有点的PFH特征信息

//3、计算所有点的PFH特征信息
//
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PFHEstimation<PointInT, PointNT, PointOutT>::computeFeature(PointCloudOut&  output)
{// 清除特征map信息feature_map_.clear();std::queue<std::pair<int, int> > empty;std::swap(key_list_, empty);//初始化PFH特征维度大小5^3=125,并初始化为{0}pfh_histogram_.setZero(nr_subdiv_ * nr_subdiv_ * nr_subdiv_);//分配需要参数vector的大小std::vector<int> nn_indices(k_);std::vector<float> nn_dists(k_);output.is_dense = true;// 稠密点云数据if (input_->is_dense){// 对每一个索引值进行遍历执行for (std::size_t idx = 0; idx < indices_->size(); ++idx){//点的最近邻域搜索if (this->searchForNeighbors((*indices_)[idx],  search_parameter_, nn_indices, nn_dists) == 0){//如果最近邻域搜索失败,则将该点的PFH值重置为NAN无效值,跳过该点for (Eigen::Index d = 0; d < pfh_histogram_.size(); ++d)output.points[idx].histogram[d] =  std::numeric_limits<float>::quiet_NaN();output.is_dense = false;continue;}// 估计每个patch的PFH特征computePointPFHSignature(*surface_, *normals_, nn_indices,  nr_subdiv_, pfh_histogram_);// 将PFH特征特征信息拷贝到输出的数据中for (Eigen::Index d = 0; d < pfh_histogram_.size(); ++d)output.points[idx].histogram[d] = pfh_histogram_[d];}}else{// Iterating over the entire index vectorfor (std::size_t idx = 0; idx < indices_->size(); ++idx){//点的最近邻域搜索和无效值判断if (!isFinite((*input_)[(*indices_)[idx]]) ||this->searchForNeighbors((*indices_)[idx],  search_parameter_, nn_indices, nn_dists) == 0){//如果最近邻域搜索失败,则将该点的PFH值重置为NAN无效值,跳过该点for (Eigen::Index d = 0; d < pfh_histogram_.size(); ++d)output.points[idx].histogram[d] =  std::numeric_limits<float>::quiet_NaN();output.is_dense = false;continue;}// 估计每个patch的PFH特征computePointPFHSignature(*surface_, *normals_, nn_indices,  nr_subdiv_, pfh_histogram_);// 将PFH特征特征信息拷贝到输出的数据中for (Eigen::Index d = 0; d < pfh_histogram_.size(); ++d)output.points[idx].histogram[d] = pfh_histogram_[d];}}
}

4、算法使用示例

/*****************************************************************//**
* \file   PCLPFHFeaturemain.cpp
* \brief  
*
* \author YZS
* \date   January 2025
*********************************************************************/
#include<iostream>
#include <vector>
#include <ctime>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/auto_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/pfh.h>//包含PFH计算的模块
using namespace std;
void PCLPFHFeature()
{//加载点云数据pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new  pcl::PointCloud<pcl::PointXYZRGB>());std::string fileName = "E:/fragment.pcd";pcl::io::load(fileName, *cloud);std::cout << "Cloud Size:" << cloud->points.size() << std::endl;//计算点云数据的法向量pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;ne.setInputCloud(cloud);pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new  pcl::search::KdTree<pcl::PointXYZRGB>());ne.setSearchMethod(tree);pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new  pcl::PointCloud<pcl::Normal>);ne.setRadiusSearch(0.02);ne.compute(*cloud_normals);//计算点云数据的PFH特征信息//pcl::PFHEstimation PFH特征估计对象pcl::PFHEstimation<pcl::PointXYZRGB, pcl::Normal, pcl::PFHSignature125>  pfh_estimation;// 设置需要计算PFH的点云数据pfh_estimation.setInputCloud(cloud);// 设置需要计算PFH的点云数据对应的法向量pfh_estimation.setInputNormals(cloud_normals);//设置最近KDtree方法pfh_estimation.setSearchMethod(tree);//创建保存PFH特征信息的对象pfh_featurespcl::PointCloud<pcl::PFHSignature125>::Ptr pfh_features(new  pcl::PointCloud<pcl::PFHSignature125>);//设置搜索的邻域半径pfh_estimation.setRadiusSearch(0.08);//设置启用缓存计算结果,加快速度pfh_estimation.setUseInternalCache(true);// 计算PFH特征信息将结构保存到pfh_features中pfh_estimation.compute(*pfh_features);// 输出索引为2000的PFH特征信息pcl::PFHSignature125 descriptor = (*pfh_features)[2000];std::cout << descriptor << std::endl;
}
int main(int argc, char* argv[])
{PCLPFHFeature();std::cout << "Hello PCL World!" << std::endl;std::system("pause");return 0;
}

结果:只输出部分

5、PFH特征的的优缺点

1、PFH的优点

        1、该方法的优点在于对噪声和遮挡具有较强的抗干扰能力,适用于复杂场景下的三维物体识别与分类。

2、PFH的缺点:

        1、计算复杂度较高。假定点云P由n个点构成,且点云分布均匀,每个点在半径为r的邻域内平均能找到k个近邻点。那么,对于每个点计算点特征直方图(PFH)的时间复杂度为O(k²),因此,整个点云的PFH理论计算复杂度为O(nk²)。在实时或接近实时的应用场景中,对于密集点云的PFH计算,O(nk²)的计算复杂度显然不尽如人意,成为了一个显著的性能瓶颈。

        2、存在大量重复计算。在计算PFH的三个特征元素时,邻域内任意两点都需要分别计算其三个特征元素值。即便相邻点的邻域可能不完全相同,但它们往往包含许多相同的近邻点(随着邻域半径的增加,这种重复的近邻点会更多)。这些共同的近邻点会被重复配对并计算特征元素值。尽管相关论文和PCL库中引入了高速缓存机制,将重复计算的开销转化为查找开销,但整体效率提升并不显著。

        至此完成第十四节PCL库点云特征之PFH点特征直方图学习,下一节我们将进入《PCL库中点云特征之FPFH特征描述》的学习。 

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

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

相关文章

5. CSS引入方式

5.1 CSS的三种样式 按照 CSS 样式书写的位置(或者引入的方式)&#xff0c;CSS样式表可以分为三大类&#xff1a; 1.行内样式表&#xff08;行内式&#xff09; 2.内部样式表&#xff08;嵌入式&#xff09; 3. 外部样式表&#xff08;链接式&#xff09; 5.2 内部样式表 …

为什么ip属地一会河南一会江苏

在使用互联网的过程中&#xff0c;许多用户可能会遇到这样一个问题&#xff1a;自己的IP属地一会儿显示为河南&#xff0c;一会儿又变成了江苏。这种现象可能会让人感到困惑&#xff0c;甚至产生疑虑&#xff0c;担心自己的网络活动是否受到了某种影响。为了解答这一疑问&#…

jmeter性能测试例子

目录 一、介绍 二、操作例子 设置线程数 添加同步定时器 添加聚合报告 一、介绍 在软件测试中&#xff0c;一般用jmeter来对接口做性能测试&#xff0c;对对接口进行一个压力的测试。 简述&#xff1a; 在接口的线程中设置线程的数量和时间&#xff0c;添加一个定时器…

PDFelement 特别版

Wondershare PDFelement Pro 是一款非常强大的PDF编辑软件&#xff0c;它允许用户轻松地编辑、转换、创建和管理PDF文件。这个中文特别版的软件具有许多令人印象深刻的功能&#xff0c;PDFelement Pro 提供了丰富的编辑功能&#xff0c;可以帮助用户直接在PDF文件中添加、删除、…

【OpenCV】使用Python和OpenCV实现火焰检测

1、 项目源码和结构&#xff08;转&#xff09; https://github.com/mushfiq1998/fire-detection-python-opencv 2、 运行环境 # 安装playsound&#xff1a;用于播放报警声音 pip install playsound # 安装opencv-python&#xff1a;cv2用于图像和视频处理&#xff0c;特别是…

深入理解Mybatis原理》MyBatis的sqlSessi

sqlSessionFactory 与 SqlSession 正如其名&#xff0c;Sqlsession对应着一次数据库会话。由于数据库会话不是永久的&#xff0c;因此Sqlsession的生命周期也不应该是永久的&#xff0c;相反&#xff0c;在你每次访问数据库时都需要创建它&#xff08;当然并不是说在Sqlsession…

《HarmonyOS第一课》焕新升级,赋能开发者快速掌握鸿蒙应用开发

随着HarmonyOS NEXT发布&#xff0c;鸿蒙生态日益壮大&#xff0c;广大开发者对于系统化学习平台和课程的需求愈发强烈。近日&#xff0c;华为精心打造的《HarmonyOS第一课》全新上线&#xff0c;集“学、练、考”于一体&#xff0c;凭借多维融合的教学模式与系统课程设置&…

springboot集成整合工作流,activiti审批流,整合实际案例,流程图设计,流程自定义,表单配置自定义,代码demo流程

前言 activiti工作流引擎项目&#xff0c;企业erp、oa、hr、crm等企事业办公系统轻松落地&#xff0c;一套完整并且实际运用在多套项目中的案例&#xff0c;满足日常业务流程审批需求。 一、项目形式 springbootvueactiviti集成了activiti在线编辑器&#xff0c;流行的前后端…

《探秘计算机视觉与深度学习:开启智能视觉新时代》

《探秘计算机视觉与深度学习&#xff1a;开启智能视觉新时代》 一、追溯起源&#xff1a;从萌芽到崭露头角二、核心技术&#xff1a;解锁智能视觉的密码&#xff08;一&#xff09;卷积神经网络&#xff08;CNN&#xff09;&#xff1a;图像识别的利器&#xff08;二&#xff0…

Vmware安装centos

用来记录自己安装的过程 一、创建虚拟机安装centos镜像 点击完成后&#xff0c;等待一会会进入centos的系统初始化界面 二、centos初始化配置 三、配置网络 1、虚拟网络编辑器&#xff0c;开启VMnet1、VMnet8的DHCP vmware左上角工具栏&#xff0c;点击【编辑】->【虚拟网…

Unity-Mirror网络框架-从入门到精通之Chat示例

文章目录 前言Chat聊天室Authentication授权ChatAuthenticatorChat示例中的授权流程聊天Chat最后 前言 在现代游戏开发中&#xff0c;网络功能日益成为提升游戏体验的关键组成部分。Mirror是一个用于Unity的开源网络框架&#xff0c;专为多人游戏开发设计。它使得开发者能够轻…

uniapp-vue3 实现, 一款带有丝滑动画效果的单选框组件,支持微信小程序、H5等多端

采用 uniapp-vue3 实现, 是一款带有丝滑动画效果的单选框组件&#xff0c;提供点状、条状的动画过渡效果&#xff0c;支持多项自定义配置&#xff0c;适配 web、H5、微信小程序&#xff08;其他平台小程序未测试过&#xff0c;可自行尝试&#xff09; 可到插件市场下载尝试&…

深度学习GPU服务器推荐:打造高效运算平台

文章来源于百家号&#xff1a;GPU服务器厂家 在深度学习和人工智能领域&#xff0c;一个高性能的GPU服务器是研究和开发工作的关键。今天&#xff0c;我们将为大家推荐一款基于详细硬件配置表的深度学习GPU服务器&#xff0c;它专为高效运算和数据处理而设计。 一、机箱设计 …

78、使用爱芯派2_AX630C开发板 3.2T高有效算力 低功耗 支持AI-ISP真黑光实验

基本思想:使用爱心元智最新的版本开发板进行实验 AX630C、AX620Q 都是 620E 这一代 一、参考这个官方教程,先把代码在本地交叉编译完成 https://github.com/AXERA-TECH/ax620e_bsp_sdk 然后在拷贝到620c设备上 root@ax630c:~/ax620e_bsp_sdk/msp/out/arm64_glibc/bin# ./…

C语言 扫雷程序设计

目录 1.main函数 2.菜单打印menu函数 3.游戏game函数 4.宏定义 5.界面初始化 6.打印界面 7.设置雷 8.统计排查坐标周围雷的个数 9.排查雷 10.总代码 test.c代码 game.h代码 game.c代码 结语&#xff1a; 一个简单的扫雷游戏&#xff0c;通过宏定义可以修改行列的…

《高速公路警察模拟器》

一个引人入胜的警察故事在等着你&#xff0c;你可以选择扮演男警官或女警官。公路警察模拟器》拥有休闲和模拟两种游戏模式&#xff0c;将两个世界的精华结合在一起&#xff1a;在身临其境的虚拟环境中自由驾驶和行走&#xff0c;在故事驱动的游戏中解决各种令人兴奋的案件。探…

EasyGBS小知识:如何确保摄像机的网络连接稳定?

在当今数字化时代&#xff0c;视频监控系统已成为保障安全和提高效率的重要工具。然而&#xff0c;摄像机的网络连接稳定性直接关系到监控系统的可靠性和有效性。为了确保视频监控系统能够持续稳定地运行&#xff0c;我们需要从硬件、网络设置、软件与监控以及安装与维护等多个…

微服务-Eureka

Eureka的作用 使用RestTemplate完成远程调用需要被调用者的ip和端口&#xff0c;从而能够发起http请求&#xff0c;但是如果有很多个实例也更加不能有效的处理&#xff0c;而且我们又该如何知道这些实例是否健康呢。所以就有了很多的注册中心比如Eureka、Nacos等等。 服务注…

LabVIEW软件侵权分析与应对

问&#xff1a;如果涉及到LabVIEW软件的仿制或模仿&#xff0c;特别是在功能、界面等方面&#xff0c;如何判断是否构成侵权&#xff1f;该如何应对&#xff1f; 答&#xff1a;LabVIEW软件的侵权问题&#xff0c;尤其是在涉及到仿制或模仿其功能、界面、设计等方面&#xff0…

MATLAB仿真:基于GS算法的经大气湍流畸变涡旋光束波前校正仿真

GS算法流程 GS&#xff08;Gerchberg-Saxton&#xff09;相位恢复算法是一种基于傅里叶变换的最速下降算法&#xff0c;可以通过输出平面和输入平面上光束的光强分布计算出光束的相位分布。图1是基于GS算法的涡旋光束畸变波前校正系统框图&#xff0c;在该框图中&#xff0c;已…