SIFT 3D关键点检测以及SAC-IA粗配准

一、SIFT 3D关键点检测

C++

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/common/common_headers.h>
#include <pcl/keypoints/sift_keypoint.h>//导入SIFT
using namespace std;

// 基于Z梯度估计3D点云的SIFT关键点
namespace pcl
{
	template<>
	struct SIFTKeypointFieldSelector<PointXYZ>
	{
		inline float
			operator () (const PointXYZ& p) const
		{
			return p.z;
		}

	};
}


int main(int, char** argv)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);//要配准变化的点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target(new pcl::PointCloud<pcl::PointXYZ>);//目标点云(不变的)
	if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view1.pcd", *cloud) == -1)
	{
		PCL_ERROR("加载点云失败\n");
	}
	if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view2.pcd", *cloud_target) == -1)
	{
		PCL_ERROR("加载点云失败\n");
	}



	pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints1(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints2(new pcl::PointCloud<pcl::PointXYZ>);


	//SIFT
	//pcl::StopWatch watch; // 计时器
	//将点类型pcl::PointWithScale的数据转换为点类型pcl::PointXYZ的数据
	pcl::PointCloud<pcl::PointWithScale> result1;
	pcl::PointCloud<pcl::PointWithScale> result2;
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
	//-----------------------------SIFT算法参数----------------------------------
	const float min_scale = 5.f;           // 设置尺度空间中最小尺度的标准偏差          
	const int n_octaves = 3;                  // 设置尺度空间层数,越小则特征点越多           
	const int n_scales_per_octave = 15;       // 设置尺度空间中计算的尺度个数
	const float min_contrast = 0.01f;       // 设置限制关键点检测的阈值              
	//----------------------------SIFT关键点检测---------------------------------
	pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift1;//创建sift关键点检测对象)))
	sift1.setInputCloud(cloud);            // 设置输入点云
	sift1.setSearchMethod(tree);               // 创建一个空的kd树对象tree,并把它传递给sift检测对象
	sift1.setScales(min_scale, n_octaves, n_scales_per_octave);//指定搜索关键点的尺度范围
	sift1.setMinimumContrast(min_contrast);    // 设置限制关键点检测的阈值
	sift1.compute(result1);                     // 执行sift关键点检测,保存结果在result
	cout << "输入点云提取的关键点:" << result1.size() << " keypoints" << endl;
	//cout << "SIFT关键点提取用时: " << watch.getTimeSeconds() << "秒" << endl;
	copyPointCloud(result1, *keypoints1);


	pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift2;//创建sift关键点检测对象)))
	sift2.setInputCloud(cloud_target);            // 设置输入点云
	sift2.setSearchMethod(tree);               // 创建一个空的kd树对象tree,并把它传递给sift检测对象
	sift2.setScales(min_scale, n_octaves, n_scales_per_octave);//指定搜索关键点的尺度范围
	sift2.setMinimumContrast(min_contrast);    // 设置限制关键点检测的阈值
	sift2.compute(result2);                     // 执行sift关键点检测,保存结果在result
	cout << "输出点云提取的关键点:" << result2.size() << " keypoints" << endl;
	//cout << "SIFT关键点提取用时: " << watch.getTimeSeconds() << "秒" << endl;
	copyPointCloud(result2, *keypoints2);


	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer1(new pcl::visualization::PCLVisualizer("v2"));
	viewer1->setBackgroundColor(0, 0, 0);
	viewer1->setWindowName("sift");
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color1(cloud, 0.0, 255, 0.0);
	viewer1->addPointCloud<pcl::PointXYZ>(keypoints1, single_color1, "key cloud");//特征点
	viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");
	while (!viewer1->wasStopped())
	{
		viewer1->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100));
	}

	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer2(new pcl::visualization::PCLVisualizer("v2"));
	viewer2->setBackgroundColor(0, 0, 0);
	viewer2->setWindowName("sift");
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color2(cloud, 0.0, 255, 0.0);
	viewer2->addPointCloud<pcl::PointXYZ>(keypoints2, single_color2, "key cloud");//特征点
	viewer2->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");
	while (!viewer2->wasStopped())
	{
		viewer2->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100));
	}

	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer3(new pcl::visualization::PCLVisualizer("v3"));
	viewer3->setBackgroundColor(0, 0, 0);
	viewer3->setWindowName("sift");
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color3(cloud, 0.0, 255, 0.0);
	viewer3->addPointCloud<pcl::PointXYZ>(cloud, single_color3, "sample cloud");
	viewer3->addPointCloud<pcl::PointXYZ>(keypoints1, "key cloud");//特征点
	viewer3->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");
	viewer3->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "key cloud");
	while (!viewer3->wasStopped())
	{
		viewer3->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100));
	}

	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer4(new pcl::visualization::PCLVisualizer("v4"));
	viewer4->setBackgroundColor(0, 0, 0);
	viewer4->setWindowName("sift");
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color4(cloud, 0.0, 255, 0.0);
	viewer4->addPointCloud<pcl::PointXYZ>(cloud_target, single_color4, "sample cloud");
	viewer4->addPointCloud<pcl::PointXYZ>(keypoints2, "key cloud");//特征点
	viewer4->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");
	viewer4->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "key cloud");
	while (!viewer4->wasStopped())
	{
		viewer4->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100));
	}



	return 0;
}

关键代码解析: 

// 基于Z梯度估计3D点云的SIFT关键点
namespace pcl
{
	template<>
	struct SIFTKeypointFieldSelector<PointXYZ>
	{
		inline float
			operator () (const PointXYZ& p) const
		{
			return p.z;
		}

	};
}
  1. namespace pcl { }:这个代码块定义了一个命名空间 pcl,其中包含了一些PCL(点云库)的相关功能。

  2. template<> struct SIFTKeypointFieldSelector<PointXYZ>:这是一个模板特化,它告诉编译器对于 PointXYZ 类型的点云,如何选择用于SIFT关键点检测的字段。

  3. inline float operator () (const PointXYZ& p) const { return p.z; }:这是一个重载的函数调用运算符,它接受一个 PointXYZ 类型的参数并返回一个浮点数。在这种情况下,它选择了点云中每个点的 Z 坐标作为特征值,即特征点的梯度值。

通过这段代码,我们告诉SIFT算法应该根据点云中每个点的Z坐标来选择特征点,而不是使用默认的X或Y坐标。这种方式可能会在垂直方向上更好地捕获点云的结构,因为Z坐标通常代表了点云中的高度信息。

对于这段代码的参数设置,主要关注的是选择适当的特征点字段。在这个例子中,我们选择了Z坐标作为特征值,但根据具体的应用场景,你可以选择其他字段,比如强度、法向量等。选择合适的字段会影响到SIFT算法检测到的特征点的质量和数量。

 

pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints1(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints2(new pcl::PointCloud<pcl::PointXYZ>);


	//SIFT
	//pcl::StopWatch watch; // 计时器
	//将点类型pcl::PointWithScale的数据转换为点类型pcl::PointXYZ的数据
	pcl::PointCloud<pcl::PointWithScale> result1;
	pcl::PointCloud<pcl::PointWithScale> result2;
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
	//-----------------------------SIFT算法参数----------------------------------
	const float min_scale = 5.f;           // 设置尺度空间中最小尺度的标准偏差          
	const int n_octaves = 3;                  // 设置尺度空间层数,越小则特征点越多           
	const int n_scales_per_octave = 15;       // 设置尺度空间中计算的尺度个数
	const float min_contrast = 0.01f;       // 设置限制关键点检测的阈值              
	//----------------------------SIFT关键点检测---------------------------------
	pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift1;//创建sift关键点检测对象)))
	sift1.setInputCloud(cloud);            // 设置输入点云
	sift1.setSearchMethod(tree);               // 创建一个空的kd树对象tree,并把它传递给sift检测对象
	sift1.setScales(min_scale, n_octaves, n_scales_per_octave);//指定搜索关键点的尺度范围
	sift1.setMinimumContrast(min_contrast);    // 设置限制关键点检测的阈值
	sift1.compute(result1);                     // 执行sift关键点检测,保存结果在result
	cout << "输入点云提取的关键点:" << result1.size() << " keypoints" << endl;
	//cout << "SIFT关键点提取用时: " << watch.getTimeSeconds() << "秒" << endl;
	copyPointCloud(result1, *keypoints1);
  1. pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints1(new pcl::PointCloud<pcl::PointXYZ>);:创建一个指向包含检测到的关键点的点云的指针。

  2. pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints2(new pcl::PointCloud<pcl::PointXYZ>);:创建另一个指向点云的指针,用于存储另一组检测到的关键点。

  3. pcl::PointCloud<pcl::PointWithScale> result1;pcl::PointCloud<pcl::PointWithScale> result2;:创建两个点云对象,用于存储SIFT算法检测到的特征点,其中pcl::PointWithScale 包含了点的三维坐标以及尺度信息。

  4. pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());:创建一个KD树搜索对象的指针,用于在点云中搜索最近邻点。

  5. const float min_scale = 5.f;const int n_octaves = 3;const int n_scales_per_octave = 15;const float min_contrast = 0.01f;:定义了SIFT算法的参数。这些参数影响着特征点的检测结果。

    • min_scale:设置尺度空间中最小尺度的标准偏差,即特征点的最小尺度。
    • n_octaves:设置尺度空间层数,即金字塔的层数,层数越大可以检测到尺度更大范围的特征。
    • n_scales_per_octave:设置尺度空间中计算的尺度个数,影响特征点的密度。
    • min_contrast:设置限制关键点检测的阈值,用于确定哪些特征点被认为是有效的。
  6. pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift1;:创建一个SIFT关键点检测对象,指定输入点的类型为pcl::PointXYZ,输出点的类型为pcl::PointWithScale

  7. sift1.setInputCloud(cloud);:设置输入点云,即要在其上执行SIFT关键点检测的点云。

  8. sift1.setSearchMethod(tree);:设置SIFT算法中使用的搜索方法为KD树搜索。

  9. sift1.setScales(min_scale, n_octaves, n_scales_per_octave);:设置SIFT算法中搜索关键点的尺度范围。

  10. sift1.setMinimumContrast(min_contrast);:设置SIFT算法中限制关键点检测的阈值。

  11. sift1.compute(result1);:执行SIFT关键点检测,并将检测到的关键点保存在 result1 中。

  12. cout << "输入点云提取的关键点:" << result1.size() << " keypoints" << endl;:输出检测到的关键点数量。

  13. copyPointCloud(result1, *keypoints1);:将检测到的关键点从 result1 复制到 keypoints1 中,转换为普通的 pcl::PointXYZ 类型的点。

这些参数的设置会影响SIFT算法检测到的特征点的数量和质量。例如,调整最小尺度、尺度空间层数和尺度个数会影响特征点的分布和密度,而调整最小对比度阈值会影响检测到的特征点的质量。

结果:

输入点云的关键点 

 输出点云的关键点 

输入点云的关键点与输入点云一起展示  

输出点云的关键点与输出点云一起展示   

 

二、SIFT 3D关键点检测及SAC-IA粗配准  

C++

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/io.h>
#include <pcl/keypoints/iss_3d.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/features/fpfh_omp.h>  
#include <pcl/common/common_headers.h>
#include <pcl/registration/ia_ransac.h>

//导入SIFT
#include <pcl/keypoints/sift_keypoint.h>
using namespace std;

// 基于Z梯度估计3D点云的SIFT关键点
namespace pcl
{
	template<>
	struct SIFTKeypointFieldSelector<PointXYZ>
	{
		inline float
			operator () (const PointXYZ& p) const
		{
			return p.z;
		}

	};
}

void extract_keypoint(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& keypoint)
{
	//SIFT
	pcl::StopWatch watch; // 计时器

	//将点类型pcl::PointWithScale的数据转换为点类型pcl::PointXYZ的数据
	pcl::PointCloud<pcl::PointWithScale> result;

	//-----------------------------SIFT算法参数----------------------------------
	const float min_scale = 5.f;           // 设置尺度空间中最小尺度的标准偏差          
	const int n_octaves = 3;                  // 设置尺度空间层数,越小则特征点越多           
	const int n_scales_per_octave = 15;       // 设置尺度空间中计算的尺度个数
	const float min_contrast = 0.01f;       // 设置限制关键点检测的阈值              
	//----------------------------SIFT关键点检测---------------------------------
	pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;//创建sift关键点检测对象)))

	sift.setInputCloud(cloud);            // 设置输入点云
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
	sift.setSearchMethod(tree);               // 创建一个空的kd树对象tree,并把它传递给sift检测对象
	sift.setScales(min_scale, n_octaves, n_scales_per_octave);//指定搜索关键点的尺度范围
	sift.setMinimumContrast(min_contrast);    // 设置限制关键点检测的阈值
	sift.compute(result);                     // 执行sift关键点检测,保存结果在result
	cout << "Extracted " << result.size() << " keypoints" << endl;
	//cout << "SIFT关键点提取用时: " << watch.getTimeSeconds() << "秒" << endl;
	copyPointCloud(result, *keypoint);

}
pcl::PointCloud<pcl::FPFHSignature33>::Ptr compute_fpfh_feature(pcl::PointCloud<pcl::PointXYZ>::Ptr& keypoint)
{
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree;
	pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
	pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;
	n.setInputCloud(keypoint);
	n.setSearchMethod(tree);
	n.setKSearch(10);
	n.compute(*normals);
	pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfh(new pcl::PointCloud<pcl::FPFHSignature33>);
	pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> f;
	f.setNumberOfThreads(8);
	f.setInputCloud(keypoint);
	f.setInputNormals(normals);
	f.setSearchMethod(tree);
	f.setRadiusSearch(50);
	f.compute(*fpfh);

	return fpfh;
}
pcl::PointCloud<pcl::PointXYZ>::Ptr sac_align(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr s_k, pcl::PointCloud<pcl::PointXYZ>::Ptr t_k, pcl::PointCloud<pcl::FPFHSignature33>::Ptr sk_fpfh, pcl::PointCloud<pcl::FPFHSignature33>::Ptr tk_fpfh)
{
	pcl::SampleConsensusInitialAlignment<pcl::PointXYZ, pcl::PointXYZ, pcl::FPFHSignature33> scia;
	scia.setInputSource(s_k);
	scia.setInputTarget(t_k);
	scia.setSourceFeatures(sk_fpfh);
	scia.setTargetFeatures(tk_fpfh);
	scia.setMinSampleDistance(7);///参数:设置采样点之间的最小距离,满足的被当做采样点
	scia.setNumberOfSamples(100);设置每次迭代设置采样点的个数(这个参数多可以增加配准精度)
	scia.setCorrespondenceRandomness(6);//设置选择随机特征对应点时要使用的邻域点个数。值越大,特征匹配的随机性就越大
	pcl::PointCloud<pcl::PointXYZ>::Ptr sac_result(new pcl::PointCloud<pcl::PointXYZ>);
	scia.align(*sac_result);
	pcl::transformPointCloud(*cloud, *sac_result, scia.getFinalTransformation());
	return sac_result;
}
int main(int, char** argv)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);//要配准变化的点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target(new pcl::PointCloud<pcl::PointXYZ>);//目标点云(不变的)
	if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view1.pcd", *cloud) == -1)
	{
		PCL_ERROR("加载点云失败\n");
	}
	if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view2.pcd", *cloud_target) == -1)
	{
		PCL_ERROR("加载点云失败\n");
	}

	boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer1(new pcl::visualization::PCLVisualizer("v1"));
	viewer1->setBackgroundColor(0, 0, 0);  //设置背景颜色为黑色
	// 对目标点云着色可视化 (red).
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color1(cloud_target, 255, 0, 0);
	viewer1->addPointCloud<pcl::PointXYZ>(cloud_target, target_color1, "target cloud");
	viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");
	// 对源点云着色可视化 (green).
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>input_color1(cloud, 0, 255, 0);
	viewer1->addPointCloud<pcl::PointXYZ>(cloud, input_color1, "input cloud");
	viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "input cloud");
	while (!viewer1->wasStopped())
	{
		viewer1->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100));
	}

	///粗配准
	pcl::PointCloud<pcl::PointXYZ>::Ptr s_k(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr t_k(new pcl::PointCloud<pcl::PointXYZ>);
	extract_keypoint(cloud, s_k);
	extract_keypoint(cloud_target, t_k);
	pcl::PointCloud<pcl::FPFHSignature33>::Ptr sk_fpfh = compute_fpfh_feature(s_k);
	pcl::PointCloud<pcl::FPFHSignature33>::Ptr tk_fpfh = compute_fpfh_feature(t_k);
	pcl::PointCloud<pcl::PointXYZ>::Ptr result(new pcl::PointCloud<pcl::PointXYZ>);
	result = sac_align(cloud, s_k, t_k, sk_fpfh, tk_fpfh);


	boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer2(new pcl::visualization::PCLVisualizer("v1"));
	viewer2->setBackgroundColor(0, 0, 0);  //设置背景颜色为黑色
	// 对目标点云着色可视化 (red).
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color2(cloud_target, 255, 0, 0);
	viewer2->addPointCloud<pcl::PointXYZ>(cloud_target, target_color2, "target cloud");
	viewer2->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");
	// 对源点云着色可视化 (green).
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>input_color2(result, 0, 255, 0);
	viewer2->addPointCloud<pcl::PointXYZ>(result, input_color2, "input cloud");
	viewer2->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "input cloud");
	while (!viewer2->wasStopped())
	{
		viewer2->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100));
	}


	return 0;
}

关键代码解析:

我之前在iss关键点检测以及SAC-IA粗配准-CSDN博客

和本章第一部分已经解释了大部分函数,这里就不赘述了

结果:

输入点云与输出点云

配准后的输入点云与输出点云,实际效果相对较好,运行不算慢,只要一两分钟就能出结果  

 

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

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

相关文章

C#查找字符串中的所有数字: 面向对象的自定义方法 vs 使用char.IsDigit()方法

目录 一、涉及到的方法 1.面向对象的自定义方法 2.面向对象编程技术定义 3.使用char.IsDigit()方法 二、实例 1.源码 2.生成效果 一、涉及到的方法 1.面向对象的自定义方法 查找字符串中的所有数字时&#xff0c;首先将所有数字存储到一个字符串数组中&#xff0c;然后…

《软件方法(下)》8.2.5.1 类名中是否有形容词(202402更新)

8.2.5.1 类名中是否有形容词 如果存在“形容词&#xff08;的&#xff09;名词”这样的类名&#xff0c;例如“待支付&#xff08;的&#xff09;订单”、“合适&#xff08;的&#xff09;会议室”&#xff0c;可以先把形容词从类名移除&#xff0c;转成类的一个状态属性。很…

Three.JS教程5 threejs中的材质

Three.JS教程5 threejs中的材质 一、什么是Three.js材质&#xff1f;二、Three.js的材质类型1. 材质类型2. 材质的共用属性&#xff08;1&#xff09;.alphaHash : Boolean&#xff08;2&#xff09;.alphaTest : Float&#xff08;3&#xff09;.alphaToCoverage : Boolean&am…

智胜未来,新时代IT技术人风口攻略-第三版(弃稿)

文章目录 前言鸿蒙生态科普调研人员画像高校助力鸿蒙高校鸿蒙课程开设占比教研力量并非唯一原因 机构入场红利机构鸿蒙课程开设占比机构对鸿蒙的一些诉求 企业布局规划全盘接纳仍需一段时间企业对鸿蒙的一些诉求 鸿蒙实际体验高校用户群体场景分析企业用户群体场景分析培训机构…

无人驾驶控制算法LQR和MPC的仿真实现

1 首先来说说LQR 1.1 Problem Statement 首先我们简单的假设一个物理系统&#xff0c;在光滑的一维地面上有一个质量为 m m m 的滑块&#xff0c;初始位置与初始速度都为 0 0 0&#xff0c;现需要设计控制器&#xff0c;在传感器测得滑块位置 x x x 的基础上&#xff0c;为…

Flutter 3.19 发布,快来看看有什么更新吧?

参考链接&#xff1a;https://medium.com/flutter/whats-new-in-flutter-3-19-58b1aae242d2 新年假期的尾巴&#xff0c;Flutter 迎来了 3.19 更新&#xff0c;该版本带来了 Gemini&#xff08;Google’s most capable AI &#xff09; 的 Dart SDK&#xff0c;更好控制动画颗粒…

扶贫|精准扶贫管理系统|基于Springboot的精准扶贫管理系统设计与实现(源码+数据库+文档)

精准扶贫管理系统目录 目录 基于Springboot的精准扶贫管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员模块的实现 &#xff08;1&#xff09;用户信息管理 &#xff08;2&#xff09;贫困户信息管理 &#xff08;3&#xff09;新闻类型管理 &a…

【论文精读】GPT2

摘要 在单一领域数据集上训练单一任务的模型是当前系统普遍缺乏泛化能力的主要原因&#xff0c;要想使用当前的架构构建出稳健的系统&#xff0c;可能需要多任务学习。但多任务需要多数据集&#xff0c;而继续扩大数据集和目标设计的规模是个难以处理的问题&#xff0c;所以只能…

【MySQL】:DQL查询

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. DQL1.1 基本语法1.2 基础查询1.3 条件查询1.3 聚合函数 &#x1f324;️ 全篇…

【AI绘画】硬核解读Stable Diffusion(完整版) 小白必收藏!!!

手把手教你入门绘图超强的AI绘画&#xff0c;用户只需要输入一段图片的文字描述&#xff0c;即可生成精美的绘画。给大家带来了全新保姆级教程资料包 &#xff08;文末可获取&#xff09; 2022年可谓是AIGC&#xff08;AI Generated Content&#xff09;元年&#xff0c;上半年…

【Linux网络编程五】Tcp套接字编程(四个版本服务器编写)

【Linux网络编程五】Tcp套接字编程(四个版本服务器编写&#xff09; [Tcp套接字编程]一.服务器端进程&#xff1a;1.创建套接字2.绑定网络信息3.设置监听状态4.获取新连接5.根据新连接进行通信 二.客户端进程&#xff1a;1.创建套接字2.连接服务器套接字3.连接成功后进行通信 三…

JavaScript中的变量监听:实时捕捉变化的利器

JavaScript中的变量监听&#xff1a;实时捕捉变化的利器 在JavaScript开发中&#xff0c;经常需要监听变量的改变&#xff0c;并在变量值发生变化时执行相应的操作。这种实时捕捉变化的功能对于构建交互性强的应用程序至关重要。本文将介绍如何在JavaScript中监听变量的改变&am…

模型 4C(消费者、成本、编译、沟通)理论

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_总纲目录。重在提升认知。以消费者为中心。 1 4C(消费者、成本、编译、沟通)理论的应用 1.1 4C理论在电子商务中的应用 亚马逊是4C营销战略的成功案例。以下是对亚马逊应用4C理论的详细解读&#xff1a; 消费者&a…

【JavaEE Spring 项目】博客系统

博客系统 前⾔项⽬介绍1. 准备⼯作1.1 数据准备1.2 创建项⽬1.3 准备前端⻚⾯1.4 配置配置⽂件1.5 测试 2. 项⽬公共模块2.1 实体类的编写2.2 公共层 3. 业务代码3.1 持久层3.2 实现博客列表3.3 实现博客详情3.4 实现登陆令牌技术JWT令牌介绍JWT令牌⽣成和校验 3.5 实现强制要求…

Python入门知识点分享——(二十一)多继承和运算符重载

在介绍新的知识之前&#xff0c;我们先对之前的内容做一点补充&#xff0c;在面向对象编程的过程中&#xff0c;一个对象常常被要求具备多方面的功能&#xff0c;从而和多个类产生联系&#xff0c;而这一步的实现就用到了“多继承”。多继承是指一个子类可以继承自多个父类&…

【Linux】Linux编译器-gcc/g++ Linux项目自动化构建工具-make/Makefile

目录 Linux编译器-gcc/g使用 1.背景知识 Linux中头文件的目录在 Linux 库 条件编译的典型应用 2.gcc如何完成 动态库 vs 静态库 debug && release Linux项目自动化构建工具-make/Makefile 背景 用法 特殊符号 Linux编译器-gcc/g使用 1.背景知识 预处理&am…

LabVIEW高效电磁阀性能测试

LabVIEW高效电磁阀性能测试 在核电站的安全运营中&#xff0c;电磁阀作为关键组件&#xff0c;其性能的可靠性至关重要。设计一套基于LabVIEW的电磁阀测试平台&#xff0c;既能精准测试电磁阀的多项性能指标&#xff0c;又能提高检修效率与准确性&#xff0c;进而保障核电站的…

Mock.js

在开发后端的应用中&#xff0c;我们使用postman来测试接口&#xff0c;观察和验证前后端之间的数据传递是否正常。 在开发前端的应用中&#xff0c;我们使用Mock.js来模拟后端服务&#xff0c;以便进行前端业务逻辑的开发和测试。 一般情况下&#xff0c;个人开发或者小团队开…

Codeforces Round 919 (Div. 2)题解(A-E)

https://codeforces.com/contest/1920 A Satisfying Constraints 链接&#xff1a;A - Satisfying Constraints 代码 #include <bits/stdc.h> using namespace std; int main() {int T;cin >> T;while(T--){int n;scanf("%d", &n);vector<int&…

算法沉淀——BFS 解决 FloodFill 算法(leetcode真题剖析)

算法沉淀——BFS 解决 FloodFill 算法 01.图像渲染02.岛屿数量03.岛屿的最大面积04.被围绕的区域 BFS&#xff08;广度优先搜索&#xff09;解决 Flood Fill 算法的基本思想是通过从起始点开始&#xff0c;逐层向外扩展&#xff0c;访问所有与起始点相连且具有相同特性&#xf…