当前位置: 首页 > news >正文

[自动驾驶-传感器融合] 多激光雷达的外参标定

文章目录

  • 引言
  • 外参标定原理
  • ICP匹配示例
  • 参考文献

引言

多激光雷达系统通常用于自动驾驶或机器人,每个雷达的位置和姿态不同,需要将它们的数据统一到同一个坐标系下。多激光雷达外参标定的核心目标是通过计算不同雷达坐标系之间的刚性变换关系(旋转矩阵 R R R 和平移向量 t t t),将多个雷达的点云数据统一到同一坐标系下。具体需求包括:

  • 数据融合:消除多雷达间的位姿差异,生成全局一致的点云。
  • 减少累积误差:避免多传感器数据因坐标系不统一导致的定位与建图误差。
  • 提升感知精度:为自动驾驶或机器人提供更可靠的环境感知能力。

外参标定原理

外参标定本质是求解两个坐标系之间的最优变换参数,设雷达A的坐标系为源坐标系,雷达B为目标坐标系。对于同一物理点 P P P,其在两个坐标系下的坐标分别为 P A P_A PA P B P_B PB,满足:
P B = R ⋅ P A + t P_B = R \cdot P_A + t PB=RPA+t
其中 R ∈ S O ( 3 ) R \in SO(3) RSO(3) 为旋转矩阵, t ∈ R 3 t \in \mathbb{R}^3 tR3 为平移向量。

一般来说,多激光雷达的主流的外参标定方法有手动标定调参法、自动标定法、基于车辆运动轨迹的标定法。

  • 手动标定法:
    使用已知几何形状的标定物(如立方体、棋盘格),通过人工测量或标定物特征点计算外参。优点:精度高,适合实验室环境。 缺点:依赖标定物,效率低。
    基本步骤是:
    1. 将标定物放置在雷达共同视场内;
    2. 提取标定物的角点或平面;
    3. 基于最小二乘法求解 R R R t t t
  • 自动标定法:
    基本方式是利用环境中的稳定特征(如地面、建筑物边缘)自动对齐点云,优点在于无需标定物、适应性较强,但易受动态物体干扰,且要求场景特征丰富。
    多采用 ICP(Iterative Closest PointNDT(Normal Distributions Transform) 求解 R R R t t t
    ICP 通过迭代最近点匹配,最小化点对距离:
    min ⁡ R , t ∑ i = 1 N ∥ ( R ⋅ P A , i + t ) − P B , i ∥ 2 \min_{R,t} \sum_{i=1}^N \| (R \cdot P_{A,i} + t) - P_{B,i} \|^2 R,tmini=1N(RPA,i+t)PB,i2
    NDT(Normal Distributions Transform) 则将点云转换为概率密度函数,通过优化概率分布相似性求解变换。

激光雷达外参标定

  • 基于运动轨迹的标定:
    利用雷达在运动过程中采集的数据,通过里程计或SLAM生成轨迹约束。一般是联合优化多个雷达的外参和运动轨迹,再使用因子图优化(Factor Graph Optimization)等方式进行优化,求解雷达之间的运动轨迹所匹配的 R R R t t t
    这种方式适合动态环境却可在线标定,但计算复杂度高,需高精度里程计支持。

注:实际工程落地时,可不用追求高难度的优化算法,可根据具体场景选择合适的方式来进行标定

ICP匹配示例

在这篇文章中,我们可结合手动标定法与自动标定法联调方式来确保标定精度,简单操作是假设我们通过手动标定方式初步得到基准激光雷达与附属激光雷达的相对坐标变换参数 R 0 R_0 R0 t 0 t_0 t0 ,在此基础上采用 G I C P GICP GICP I C P ICP ICP等基础算法进行多次配准提高标定精度,得到最终的 R R R t t t

这里展示一个 I C P ICP ICP的使用示例:
按" 空格 "即可观察迭代匹配的效果。

#include <pcl/console/time.h>  
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
#include <pcl/visualization/pcl_visualizer.h>#include <string>typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;bool next_iteration = false;void print4x4Matrix(const Eigen::Matrix4d& matrix) {printf("Rotation matrix :\n");printf("    | %6.3f %6.3f %6.3f | \n", matrix(0, 0), matrix(0, 1),matrix(0, 2));printf("R = | %6.3f %6.3f %6.3f | \n", matrix(1, 0), matrix(1, 1),matrix(1, 2));printf("    | %6.3f %6.3f %6.3f | \n", matrix(2, 0), matrix(2, 1),matrix(2, 2));printf("Translation vector :\n");printf("t = < %6.3f, %6.3f, %6.3f >\n\n", matrix(0, 3), matrix(1, 3),matrix(2, 3));
}
/*** 此函数是查看器的回调。 当查看器窗口位于顶部时,只要按任意键,就会调用此函数。* 如果碰到“空格”; 将布尔值设置为true。* @param event* @param nothing*/
void keyboardEventOccurred(const pcl::visualization::KeyboardEvent& event,void* nothing) {if (event.getKeySym() == "space" && event.keyDown()) next_iteration = true;
}int main(int argc, char* argv[]) {// The point clouds we will be usingPointCloudT::Ptr cloud_in(new PointCloudT);   // Original point cloudPointCloudT::Ptr cloud_tr(new PointCloudT);   // Transformed point cloudPointCloudT::Ptr cloud_icp(new PointCloudT);  // ICP output point cloud//    我们检查程序的参数,设置初始ICP迭代的次数,然后尝试加载PLY文件。// Checking program argumentsif (argc < 2) {printf("Usage :\n");printf("\t\t%s file.ply number_of_ICP_iterations\n", argv[0]);PCL_ERROR("Provide one ply file.\n");return (-1);}int iterations = 1;  // Default number of ICP iterationsif (argc > 2) {// If the user passed the number of iteration as an argumentiterations = atoi(argv[2]);if (iterations < 1) {PCL_ERROR("Number of initial iterations must be >= 1\n");return (-1);}}pcl::console::TicToc time;time.tic();if (pcl::io::loadPLYFile(argv[1], *cloud_in) < 0) {PCL_ERROR("Error loading cloud %s.\n", argv[1]);return (-1);}std::cout << "\nLoaded file " << argv[1] << " (" << cloud_in->size()<< " points) in " << time.toc() << " ms\n"<< std::endl;// 我们使用刚性矩阵变换来变换原始点云。// cloud_in包含原始点云。// cloud_tr和cloud_icp包含平移/旋转的点云。// cloud_tr是我们将用于显示的备份(绿点云)。// Defining a rotation matrix and translation vectorEigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity();// A rotation matrix (see https://en.wikipedia.org/wiki/Rotation_matrix)double theta = M_PI / 8;  // The angle of rotation in radianstransformation_matrix(0, 0) = std::cos(theta);transformation_matrix(0, 1) = -sin(theta);transformation_matrix(1, 0) = sin(theta);transformation_matrix(1, 1) = std::cos(theta);// A translation on Z axis (0.4 meters)transformation_matrix(2, 3) = 0.4;// Display in terminal the transformation matrixstd::cout << "Applying this rigid transformation to: cloud_in -> cloud_icp"<< std::endl;print4x4Matrix(transformation_matrix);// Executing the transformationpcl::transformPointCloud(*cloud_in, *cloud_icp, transformation_matrix);*cloud_tr = *cloud_icp;  // We backup cloud_icp into cloud_tr for later use// 这是ICP对象的创建。 我们设置ICP算法的参数。// setMaximumIterations(iterations)设置要执行的初始迭代次数(默认值为1)。// 然后,我们将点云转换为cloud_icp。// 第一次对齐后,我们将在下一次使用该ICP对象时(当用户按下“空格”时)将ICP最大迭代次数设置为1。// The Iterative Closest Point algorithmtime.tic();pcl::IterativeClosestPoint<PointT, PointT> icp;icp.setMaximumIterations(iterations);icp.setInputSource(cloud_icp);icp.setInputTarget(cloud_in);icp.align(*cloud_icp);icp.setMaximumIterations(1);  // We set this variable to 1 for the next time// we will call .align () functionstd::cout << "Applied " << iterations << " ICP iteration(s) in " << time.toc()<< " ms" << std::endl;// 检查ICP算法是否收敛; 否则退出程序。// 如果返回true,我们将转换矩阵存储在4x4矩阵中,然后打印刚性矩阵转换。if (icp.hasConverged()) {// std::cout << "\nICP has converged, score is " << icp.getFitnessScore()//           << std::endl;// std::cout << "\nICP transformation " << iterations//           << " : cloud_icp -> cloud_in" << std::endl;transformation_matrix = icp.getFinalTransformation().cast<double>();print4x4Matrix(transformation_matrix);} else {PCL_ERROR("\nICP has not converged.\n");return (-1);}// Visualizationpcl::visualization::PCLVisualizer viewer("ICP demo");// Create two vertically separated viewportsint v1(0);int v2(1);viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);// The color we will be usingfloat bckgr_gray_level = 0.0;  // Blackfloat txt_gray_lvl = 1.0 - bckgr_gray_level;// Original point cloud is whitepcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_in_color_h(cloud_in, (int)255 * txt_gray_lvl, (int)255 * txt_gray_lvl,(int)255 * txt_gray_lvl);viewer.addPointCloud(cloud_in, cloud_in_color_h, "cloud_in_v1", v1);viewer.addPointCloud(cloud_in, cloud_in_color_h, "cloud_in_v2", v2);// Transformed point cloud is greenpcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_tr_color_h(cloud_tr, 20, 180, 20);viewer.addPointCloud(cloud_tr, cloud_tr_color_h, "cloud_tr_v1", v1);// ICP aligned point cloud is redpcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_icp_color_h(cloud_icp, 180, 20, 20);viewer.addPointCloud(cloud_icp, cloud_icp_color_h, "cloud_icp_v2", v2);// Adding text descriptions in each viewportviewer.addText("White: Original point cloud\nGreen: Matrix transformed point cloud", 10,15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_1", v1);viewer.addText("White: Original point cloud\nRed: ICP aligned point cloud",10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl,"icp_info_2", v2);std::stringstream ss;ss << iterations;std::string iterations_cnt = "ICP iterations = " + ss.str();viewer.addText(iterations_cnt, 10, 60, 16, txt_gray_lvl, txt_gray_lvl,txt_gray_lvl, "iterations_cnt", v2);// Set background colorviewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level,bckgr_gray_level, v1);viewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level,bckgr_gray_level, v2);// Set camera position and orientationviewer.setCameraPosition(-3.68332, 2.94092, 5.71266, 0.289847, 0.921947,-0.256907, 0);viewer.setSize(1280, 1024);  // Visualiser window size// Register keyboard callback :viewer.registerKeyboardCallback(&keyboardEventOccurred, (void*)NULL);// Display the visualiserwhile (!viewer.wasStopped()) {viewer.spinOnce();// The user pressed "space" :if (next_iteration) {// The Iterative Closest Point algorithmtime.tic();// 如果用户按下键盘上的任意键,则会调用keyboardEventOccurred函数。// 此功能检查键是否为“空格”。// 如果是,则全局布尔值next_iteration设置为true,从而允许查看器循环输入代码的下一部分:调用ICP对象以进行对齐。// 记住,我们已经配置了该对象输入/输出云,并且之前通过setMaximumIterations将最大迭代次数设置为1。icp.align(*cloud_icp);std::cout << "Applied 1 ICP iteration in " << time.toc() << " ms"<< std::endl;// 和以前一样,我们检查ICP是否收敛,如果不收敛,则退出程序。if (icp.hasConverged()) {// printf(“ 033 [11A”);// 在终端增加11行以覆盖显示的最后一个矩阵是一个小技巧。// 简而言之,它允许替换文本而不是编写新行; 使输出更具可读性。// 我们增加迭代次数以更新可视化器中的文本值。printf("\033[11A");  // Go up 11 lines in terminal output.printf("\nICP has converged, score is %+.0e\n", icp.getFitnessScore());// 这意味着,如果您已经完成了10次迭代,则此函数返回矩阵以将点云从迭代10转换为11。std::cout << "\nICP transformation " << ++iterations<< " : cloud_icp -> cloud_in" << std::endl;// 函数getFinalTransformation()返回在迭代过程中完成的刚性矩阵转换(此处为1次迭代)。transformation_matrix *=icp.getFinalTransformation().cast<double>();  // WARNING /!\ This is not accurate! For// "educational" purpose only!print4x4Matrix(transformation_matrix);  // Print the transformation between// original pose and current posess.str("");ss << iterations;std::string iterations_cnt = "ICP iterations = " + ss.str();viewer.updateText(iterations_cnt, 10, 60, 16, txt_gray_lvl,txt_gray_lvl, txt_gray_lvl, "iterations_cnt");viewer.updatePointCloud(cloud_icp, cloud_icp_color_h, "cloud_icp_v2");} else {PCL_ERROR("\nICP has not converged.\n");return (-1);}//这不是我们想要的。//如果我们将最后一个矩阵与新矩阵相乘,那么结果就是从开始到当前迭代的转换矩阵。}next_iteration = false;}return (0);
}

ICP效果示例

参考文献

[1] 姜聿于——自动驾驶感知【激光雷达】:一、标定

[2] Segal A , Hhnel D , Thrun S .Generalized-ICP[J]. 2009.DOI:10.15607/RSS.2009.V.021.

[3] Kulmer D , Tahiraj I , Chumak A ,et al.Multi-LiCa: A Motion and Targetless Multi LiDAR-to-LiDAR Calibration Framework[J].IEEE, 2025.DOI:10.1109/MFI62651.2024.10705773.

相关文章:

[自动驾驶-传感器融合] 多激光雷达的外参标定

文章目录 引言外参标定原理ICP匹配示例参考文献 引言 多激光雷达系统通常用于自动驾驶或机器人&#xff0c;每个雷达的位置和姿态不同&#xff0c;需要将它们的数据统一到同一个坐标系下。多激光雷达外参标定的核心目标是通过计算不同雷达坐标系之间的刚性变换关系&#xff08…...

怎么让呼叫中心支持高并发

基于FreeSWITCH的呼叫中心系统并发性能优化指南 在呼叫中心系统建设中&#xff0c;高并发处理能力是衡量系统稳定性和效率的核心指标。作为开源软交换平台的代表&#xff0c;FreeSWITCH凭借其线程模型和模块化架构&#xff0c;天然适合高并发场景。然而&#xff0c;实际应用中仍…...

Elasticsearch简单学习

1、依赖的导入 <!--ES依赖--> <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>2、客户端链接 RestHighLevelClient client new RestHigh…...

就像BGP中的AS_PATH一样,无论路途多远,我愿意陪你一起走——基于华为ENSP的BGP的路由负载均衡及过滤深入浅出

本篇技术博文摘要 &#x1f31f; 本文内容涵盖了BGP负载均衡的基本概念、配置技巧和在实际网络中的应用&#xff0c;包括如何在华为ENSP上实现负载均衡和路由过滤。通过配置BGP的前缀列表、ACL以及路由过滤策略&#xff0c;可以实现网络流量的精确控制和优化&#xff0c;提高网…...

valgrind 检测多线程 bug,检测 并发 bug concurrent bug parallel bug

valgrind --toolhelgrind ./your_program 如果检测的对象是大型程序&#xff0c;可以设定仅在某些函数中开启 valgrind 的检测&#xff1a; Valgrind 提供了一些客户请求&#xff08;client requests&#xff09;&#xff0c;可以在代码中插入特定的宏来控制 Valgrind 的行为。…...

游戏引擎学习第135天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾 game_asset.cpp 的创建 在开发过程中&#xff0c;不使用任何现成的游戏引擎或第三方库&#xff0c;而是直接基于 Windows 进行开发&#xff0c;因为 Windows 目前仍然是游戏的标准平台&#xff0c;因此首先在这个环境中进行…...

异步操作返回原始上下文

是什么&#xff1f; 在讨论同步上下文执行回调的概念时&#xff0c;我们首先需要了解一些基本概念&#xff1a;同步与异步操作、上下文以及回调函数。 同步与异步操作&#xff1a; 同步操作是指代码按照顺序依次执行&#xff0c;每个操作必须等待前一个操作完成才能开始。这便…...

区块链中的数字签名:安全性与可信度的核心

数字签名是区块链技术的信任基石&#xff0c;它像区块链世界的身份证和防伪标签&#xff0c;确保每一笔交易的真实性、完整性和不可抵赖性。本文会用通俗的语言&#xff0c;带你彻底搞懂区块链中的数字签名&#xff01; 文章目录 1. 数字签名是什么&#xff1f;从现实世界到区块…...

vulnhub渗透日记23:bulldog

声明 文中涉及操作均来自靶机虚拟环境&#xff0c;禁止用于真实环境&#xff0c;任何未经授权的渗透测试都是违法行为&#xff01; 开搞 首先nmap扫描目标机开放端口和服务 访问80端口 扫目录撒 发现登录口 点击web-shell提示登录后才能使用 /dev/下面查看网页源码发现村咋h…...

macOS - 使用 tmux

文章目录 安装 tmux使用更多快捷键说明 安装 tmux brew install tmux使用 在终端输入 tmux 进入 tmux 界面&#xff0c;然后 输入 Control Option B 进入交互模式 输入 % 左右分栏&#xff0c;" 上下分割 上一个窗格&#xff1a;{&#xff0c;下一个&#xff1a;} PS…...

Armbian: 轻量级 ARM 设备专用 Linux 发行版全面解析

引言 在嵌入式开发和物联网&#xff08;IoT&#xff09;领域&#xff0c;选择合适的操作系统至关重要。对于 Raspberry Pi、Orange Pi、Banana Pi 以及 Rockchip、Amlogic、Allwinner 等 ARM 平台上的单板计算机&#xff08;SBC&#xff09;&#xff0c;一个高效、轻量级并且易…...

微服务通信:用gRPC + Protobuf 构建高效API

引言 在微服务架构中&#xff0c;服务之间的通信是系统设计的核心问题之一。传统的RESTful API虽然简单易用&#xff0c;但在性能、类型安全和代码生成等方面存在一定的局限性。gRPC作为一种高性能、跨语言的RPC框架&#xff0c;结合Protobuf&#xff08;Protocol Buffers&…...

Spring Boot 整合 JMS-ActiveMQ,并安装 ActiveMQ

1. 安装 ActiveMQ 1.1 下载 ActiveMQ 访问 ActiveMQ 官方下载页面&#xff0c;根据你的操作系统选择合适的版本进行下载。这里以 Linux 系统&#xff0c;Java环境1.8版本为例&#xff0c;下载 apache-activemq-5.16.7-bin.tar.gz。 1.2 解压文件 将下载的压缩包解压到指定目…...

容器 /dev/shm 泄漏学习

容器 /dev/shm 泄漏的介绍 在容器环境中&#xff0c;/dev/shm 是一个基于 tmpfs 的共享内存文件系统&#xff0c;通常用于进程间通信&#xff08;IPC&#xff09;和临时数据存储。由于其内存特性&#xff0c;/dev/shm 的大小是有限的&#xff0c;默认情况下 Docker 容器的 /de…...

Spring Boot 3.x 基于 Redis 实现邮箱验证码认证

文章目录 依赖配置开启 QQ 邮箱 SMTP 服务配置文件代码实现验证码服务邮件服务接口实现执行流程 依赖配置 <dependencies> <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr…...

车载测试:智能座舱测试中多屏联动与语音交互的挑战

智能座舱作为汽车智能化发展的核心&#xff0c;集成了多屏联动和语音交互功能&#xff0c;为驾驶员和乘客提供更便捷的体验。然而&#xff0c;这些功能的测试面临诸多挑战&#xff0c;包括多屏同步性、噪声干扰和复杂场景的处理。本文将详细分析这些挑战&#xff0c;探讨测试方…...

C/C++输入输出(1)

1.getchar和putchar 1.1getchar() 函数原型&#xff1a; 1 int getchar(void); getchar()函数返回用户从键盘输入的字符&#xff0c;使用时不带有任何参数。 程序运行到这个命令就会暂停&#xff0c;等待用户从键盘输入&#xff0c;等同于使用cin或scanf()方法读取一个字符…...

前端面试场景题葵花宝典之四

87.场景面试之大数运算&#xff1a;超过js中number最大值的数怎么处理 在 JavaScript 中&#xff0c;Number.MAX_SAFE_INTEGER&#xff08;即 2^53 - 1&#xff0c;即 9007199254740991&#xff09;是能被安全表示的最大整数。超过此值时&#xff0c;普通的 Number 类型会出现…...

探索Elasticsearch:索引的CRUD

在企业环境中&#xff0c;Elasticsearch的索引CRUD&#xff08;创建Create、读取Read、更新Update、删除Delete&#xff09;操作是非常基础且频繁使用的功能。这些操作对于管理和维护数据至关重要&#xff0c;尤其是在处理大规模数据集和需要实时搜索与分析的应用场景中。 目录…...

Java数据结构第十六期:走进二叉树的奇妙世界(五)

专栏&#xff1a;Java数据结构秘籍 个人主页&#xff1a;手握风云 目录 一、非递归实现遍历二叉树 1.1. 二叉树的前序遍历 1.2. 二叉树的中序遍历 1.3. 二叉树的后序遍历 一、非递归实现遍历二叉树 1.1. 二叉树的前序遍历 我们这里要使用栈来进行实现。我们反向思考一下为…...

【开源免费】基于SpringBoot+Vue.JS疫情管理系统(JAVA毕业设计)

本文项目编号 T 227 &#xff0c;文末自助获取源码 \color{red}{T227&#xff0c;文末自助获取源码} T227&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

有关Java中的集合(1):List<T>和Set<T>

学习目标 核心掌握List集合了解Set集合 1.List<T> ● java.util.List。有序列表。 ● List集合元素的特点&#xff1a;有序表示存取有序&#xff08;因为有索引&#xff09;而且可以重复 ● List常用实现类&#xff1a; ArrayList、LinkedList、Vector等 1.1 常用方法…...

使用 Spring Boot 实现前后端分离的海康威视 SDK 视频监控

使用 Spring Boot 实现前后端分离的海康威视 SDK 视频监控系统&#xff0c;可以分为以下几个步骤&#xff1a; 1. 系统架构设计 前端&#xff1a;使用 Vue.js、React 或 Angular 等前端框架实现用户界面。后端&#xff1a;使用 Spring Boot 提供 RESTful API&#xff0c;负责与…...

在 Apache Tomcat 中,部署和删除项目

在 Apache Tomcat 中&#xff0c;部署和删除 WAR 文件是常见的操作。以下是详细步骤&#xff1a; 1. 删除 WAR 文件 (1) 停止应用 进入 Tomcat 的管理界面&#xff08;默认地址&#xff1a;http://localhost:8080/manager/html&#xff09;。 找到需要删除的应用&#xff0c;…...

宇树科技G1人形机器人:从炫技到实用,AI驱动下的进化跃迁‌

‌ 宇树科技的G1人形机器人近期凭借“720度回旋踢”“走梅花桩”等高难度动作频频出圈&#xff0c;成为人形机器人领域的现象级产品。 G1人形机器人看似炫技的表演背后&#xff0c;实则暗含了技术突破的深意。G1的每一次技能升级&#xff0c;都是对机器人运动控制、平衡算法和A…...

给定计算预算下的最佳LLM模型尺寸与预训练数据量分配

给定计算预算下的最佳LLM模型尺寸与预训练数据量分配 FesianXu 20250304 at Wechat Search Team 前言 如果给定了计算预算 C C C&#xff0c;如何分配LLM的模型尺寸 N N N和训练的数据量 D D D&#xff0c;才能使得模型的效果 L L L最好呢&#xff1f;笔者在此介绍一篇经典的文…...

H5DS编辑器是如何让企业快速构建动态页面

H5DS编辑器核心亮点&#xff1a; 1.拖拽式操作&#xff0c;小白友好&#xff1a;无需设计与代码基础&#xff01;通过简单拖拽元素、调整文字和动画&#xff0c;即可生成交互式H5页面。内置海量模板和素材库&#xff0c;支持自定义设计风格&#xff0c;轻松适配企业品牌需求。…...

面试题汇总(一)

熙牛医疗面经 1.平衡二叉树的概念 平衡二叉树是一种二叉搜索树&#xff0c;他的左右两个字数的高度差绝对值不超过1&#xff0c;并且左右两个子树都是一颗平衡二叉树&#xff0c;通过左旋&#xff0c;右旋&#xff0c;左右双旋&#xff0c;右左双旋&#xff0c;来保持平衡&…...

论坛系统测试报告

目录 一、项目背景二、论坛系统测试用例思维导图三、论坛系统测试3.1界面测试3.2登陆测试3.3主页测试3.4个人中心测试 四、自动化测试脚本4.1配置驱动4.2创建浏览器类4.3功能测试4.3.1登陆测试4.3.2注册测试4.3.3主页测试4.3.4帖子编辑4.3.5运行主代码 五、BUG分析六、测试总结…...

算法比赛中处理输入和输出

在算法比赛中&#xff0c;不推荐使用 Scanner 和 System.out.println()。Scanner 线程安全&#xff0c;有大量同步操作&#xff0c;读取输入时每次都要解析数据类型&#xff0c;处理大数据量时性能开销大、效率低&#xff0c;易使程序超时间限制。System.out.println() 每次调用…...