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

CloudCompare——拟合空间球

目录

  • 1.拟合球
  • 2.软件操作
  • 3.算法源码
  • 4.相关代码

在这里插入图片描述

本文由CSDN点云侠原创,CloudCompare——拟合空间球,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT生成的文章。

1.拟合球

  源码里用到了四点定球,具体计算原理如下

  已知空间内不共面的四个点,设其坐标为 A ( x 1 , y 1 , z 1 ) A(x_1,y_1,z_1) A(x1,y1,z1) B ( x 2 , y 2 , z 2 ) B(x_2,y_2,z_2) B(x2,y2,z2) C ( x 3 , y 3 , z 3 ) 、 D ( x 4 , y 4 , z 4 ) C(x_3,y_3,z_3)、D(x_4,y_4,z_4) C(x3,y3,z3)D(x4,y4,z4),设半径为 r r r,球心 O O O坐标为 ( x , y , z ) (x,y,z) (x,y,z)。利用四点到球心距离相等的性质得到如下四个方程。
( x − x 1 ) 2 + ( y − y 1 ) 2 + ( z − z 1 ) 2 = r 2 ; ( x − x 2 ) 2 + ( y − y 2 ) 2 + ( z − z 2 ) 2 = r 2 ; ( x − x 3 ) 2 + ( y − y 3 ) 2 + ( z − z 3 ) 2 = r 2 ; ( x − x 4 ) 2 + ( y − y 4 ) 2 + ( z − z 4 ) 2 = r 2 ; (x-x_1)^2 + (y-y_1)^2 +(z-z_1)^2 =r^2;\\ (x-x_2)^2 + (y-y_2)^2 +(z-z_2)^2 =r^2;\\ (x-x_3)^2 + (y-y_3)^2 +(z-z_3)^2 =r^2;\\ (x-x_4)^2 + (y-y_4)^2 +(z-z_4)^2 =r^2; (xx1)2+(yy1)2+(zz1)2=r2;(xx2)2+(yy2)2+(zz2)2=r2;(xx3)2+(yy3)2+(zz3)2=r2;(xx4)2+(yy4)2+(zz4)2=r2;

展开得:
x 2 + y 2 + z 2 − 2 ( x 1 x + y 1 y + z 1 z ) + x 1 2 + y 1 2 + z 1 2 = r 2 ① x 2 + y 2 + z 2 − 2 ( x 2 x + y 2 y + z 2 z ) + x 2 2 + y 2 2 + z 2 2 = r 2 ② x 2 + y 2 + z 2 − 2 ( x 3 x + y 3 y + z 3 z ) + x 3 2 + y 3 2 + z 3 2 = r 2 ③ x 2 + y 2 + z 2 − 2 ( x 4 x + y 4 y + z 4 z ) + x 4 2 + y 4 2 + z 4 2 = r 2 ④ x^2 + y^2 + z^2- 2(x_1x+y_1y+z_1z)+x_1^2+y_1^2 + z_1^2 = r^2 ①\\ x^2 + y^2 + z^2- 2(x_2x+y_2y+z_2z)+x_2^2+y_2^2 + z_2^2 = r^2②\\ x^2 + y^2 + z^2- 2(x_3x+y_3y+z_3z)+x_3^2+y_3^2 + z_3^2 = r^2③\\ x^2 + y^2 + z^2- 2(x_4x+y_4y+z_4z)+x_4^2+y_4^2 + z_4^2 = r^2④ x2+y2+z22(x1x+y1y+z1z)+x12+y12+z12=r2x2+y2+z22(x2x+y2y+z2z)+x22+y22+z22=r2x2+y2+z22(x3x+y3y+z3z)+x32+y32+z32=r2x2+y2+z22(x4x+y4y+z4z)+x42+y42+z42=r2

分别作①-②、③ - ④、② - ③得:
( x 1 − x 2 ) x + ( y 1 − y 2 ) y + ( z 1 − z 2 ) z = 1 / 2 ( x 1 2 − x 2 2 + y 1 2 − y 2 2 + z 1 2 − z 2 2 ) ( x 3 − x 4 ) x + ( y 3 − y 4 ) y + ( z 3 − z 4 ) z = 1 / 2 ( x 3 2 − x 4 2 + y 3 2 − y 4 2 + z 3 2 − z 4 2 ) ( x 2 − x 3 ) x + ( y 2 − y 3 ) y + ( z 2 − z 3 ) z = 1 / 2 ( x 2 2 − x 3 2 + y 2 2 − y 3 2 + z 2 2 − z 3 2 ) (x_1-x_2)x+(y_1-y_2)y+(z_1-z_2)z=1/2(x_1^2 -x_2^2 + y_1^2 -y_2^2 + z_1^2 -z_2^2 )\\ (x_3-x_4)x+(y_3-y_4)y+(z_3-z_4)z=1/2(x_3^2 -x_4^2 + y_3^2 -y_4^2 + z_3^2 -z_4^2 )\\ (x_2-x_3)x+(y_2-y_3)y+(z_2-z_3)z=1/2(x_2^2 -x_3^2 + y_2^2 -y_3^2 + z_2^2 -z_3^2 )\\ (x1x2)x+(y1y2)y+(z1z2)z=1/2(x12x22+y12y22+z12z22)(x3x4)x+(y3y4)y+(z3z4)z=1/2(x32x42+y32y42+z32z42)(x2x3)x+(y2y3)y+(z2z3)z=1/2(x22x32+y22y32+z22z32)

其对应的系数行列式可设为:

D = ∣ a b c a 1 b 1 c 1 a 2 b 2 c 2 ∣ D=\left| \begin{matrix} a & b & c\\ a_1 & b_1 & c_1 \\ a_2 & b_2 & c_2 \end{matrix} \right| D= aa1a2bb1b2cc1c2

则: a = ( x 1 − x 2 ) , b = ( y 1 − y 2 ) , c = ( z 1 − z 2 ) , a 1 = ( x 3 − x 4 ) , b 1 = ( y 3 − y 4 ) , c 1 = ( z 3 − z 4 ) , a 2 = ( x 2 − x 3 ) , b 2 = ( y 2 − y 3 ) , c 2 = ( z 2 − z 3 ) a=(x_1-x_2),b=(y_1-y_2),c=(z_1-z_2),\\a_1=(x_3-x_4),b_1=(y_3-y_4),c_1=(z_3-z_4),\\ a_2=(x_2-x_3),b_2=(y_2-y_3),c_2=(z_2-z_3) a=(x1x2),b=(y1y2),c=(z1z2),a1=(x3x4),b1=(y3y4)c1=(z3z4),a2=(x2x3),b2=(y2y3)c2=(z2z3)

常数项行列式为:

L = ∣ P Q R ∣ L=\left| \begin{matrix} P\\ Q \\ R \end{matrix} \right| L= PQR

则:
P = 1 2 ( x 1 2 − x 2 2 + y 1 2 − y 2 2 + z 1 2 − z 2 2 ) P=\frac{1}{2}(x_1^2 -x_2^2 + y_1^2 -y_2^2 + z_1^2 - z_2^2 ) P=21(x12x22+y12y22+z12z22)
Q = 1 2 ( x 3 2 − x 4 2 + y 3 2 − y 4 2 + z 3 2 − z 4 2 ) Q=\frac{1}{2}(x_3^2 -x_4^2 + y_3^2 -y_4^2 + z_3^2 - z_4^2 ) Q=21(x32x42+y32y42+z32z42)
R = 1 2 ( x 2 2 − x 3 2 + y 2 2 − y 3 2 + z 2 2 − z 3 2 ) R=\frac{1}{2}(x_2^2 -x_3^2 + y_2^2 -y_3^2 + z_2^2 - z_3^2 ) R=21(x22x32+y22y32+z22z32)

现设:
D x = ∣ P b c Q b 1 c 1 R b 2 c 2 ∣ Dx=\left| \begin{matrix} P & b & c\\ Q & b_1 & c_1 \\ R & b_2 & c_2 \end{matrix} \right| Dx= PQRbb1b2cc1c2

D y = ∣ a P c a 1 Q c 1 a 2 R c 2 ∣ Dy=\left| \begin{matrix} a & P & c\\ a_1 & Q & c_1 \\ a_2 &R & c_2 \end{matrix} \right| Dy= aa1a2PQRcc1c2

D z = ∣ a b P a 1 b 1 Q a 2 b 2 R ∣ Dz=\left| \begin{matrix} a & b & P\\ a_1 & b_1 & Q \\ a_2 &b_2 & R \end{matrix} \right| Dz= aa1a2bb1b2PQR

由线性代数中的克拉默法则可知:
x = D x D x=\frac{Dx}{D} x=DDx

y = D y D y=\frac{Dy}{D} y=DDy

z = D z D z=\frac{Dz}{D} z=DDz

2.软件操作

  通过菜单栏的'Tools > Fit > Sphere'找到该功能。
在这里插入图片描述

  选择一个或多个点云,然后启动此工具。CloudCompare将在每个点云上拟合球体基元。在控制台中,将输出以下信息:

  • center(也可以在球体实体属性中找到球体边界框的中心)
  • radius(也可以在sphere实体属性中找到)
  • 球体拟合RMS(在默认球体实体名称中调用)注意:理论上球体拟合算法可以处理高达50%的异常值。

球形点云
在这里插入图片描述
拟合结果
在这里插入图片描述
控制台输出
在这里插入图片描述

3.算法源码

GeometricalAnalysisTools::ErrorCode GeometricalAnalysisTools::DetectSphereRobust(GenericIndexedCloudPersist* cloud,double outliersRatio,CCVector3& center,PointCoordinateType& radius,double& rms,GenericProgressCallback* progressCb/*=nullptr*/,double confidence/*=0.99*/,unsigned seed/*=0*/)
{if (!cloud){assert(false);return InvalidInput;}unsigned n = cloud->size();if (n < 4)return NotEnoughPoints;assert(confidence < 1.0);confidence = std::min(confidence, 1.0 - FLT_EPSILON);//we'll need an array (sorted) to compute the mediansstd::vector<PointCoordinateType> values;try{values.resize(n);}catch (const std::bad_alloc&){//not enough memoryreturn NotEnoughMemory;}//number of samplesunsigned m = 1;const unsigned p = 4;if (n > p){m = static_cast<unsigned>(log(1.0 - confidence) / log(1.0 - pow(1.0 - outliersRatio, static_cast<double>(p))));}//for progress notificationNormalizedProgress nProgress(progressCb, m);if (progressCb){if (progressCb->textCanBeEdited()){char buffer[64];sprintf(buffer, "Least Median of Squares samples: %u", m);progressCb->setInfo(buffer);progressCb->setMethodTitle("Detect sphere");}progressCb->update(0);progressCb->start();}//now we are going to randomly extract a subset of 4 points and test the resulting sphere each timeif (seed == 0){std::random_device randomGenerator;   // non-deterministic generatorseed = randomGenerator();}std::mt19937 gen(seed);  // to seed mersenne twister.std::uniform_int_distribution<unsigned> dist(0, n - 1);unsigned sampleCount = 0;unsigned attempts = 0;double minError = -1.0;std::vector<unsigned> indexes;indexes.resize(p);while (sampleCount < m && attempts < 2*m){//get 4 random (different) indexesfor (unsigned j = 0; j < p; ++j){bool isOK = false;while (!isOK){indexes[j] = dist(gen);isOK = true;for (unsigned k = 0; k < j && isOK; ++k)if (indexes[j] == indexes[k])isOK = false;}}assert(p == 4);const CCVector3* A = cloud->getPoint(indexes[0]);const CCVector3* B = cloud->getPoint(indexes[1]);const CCVector3* C = cloud->getPoint(indexes[2]);const CCVector3* D = cloud->getPoint(indexes[3]);++attempts;CCVector3 thisCenter;PointCoordinateType thisRadius;if (ComputeSphereFrom4(*A, *B, *C, *D, thisCenter, thisRadius) != NoError)continue;//compute residualsfor (unsigned i = 0; i < n; ++i){PointCoordinateType error = (*cloud->getPoint(i) - thisCenter).norm() - thisRadius;values[i] = error*error;}const unsigned int	medianIndex = n / 2;std::nth_element(values.begin(), values.begin() + medianIndex, values.end());//the error is the median of the squared residualsdouble error = static_cast<double>(values[medianIndex]);//we keep track of the solution with the least errorif (error < minError || minError < 0.0){minError = error;center = thisCenter;radius = thisRadius;}++sampleCount;if (progressCb && !nProgress.oneStep()){//progress canceled by the userreturn ProcessCancelledByUser;}}//too many failures?!if (sampleCount < m){return ProcessFailed;}//last step: robust estimationReferenceCloud candidates(cloud);if (n > p){//e robust standard deviation estimate (see Zhang's report)double sigma = 1.4826 * (1.0 + 5.0 /(n-p)) * sqrt(minError);//compute the least-squares best-fitting sphere with the points//having residuals below 2.5 sigmadouble maxResidual = 2.5 * sigma;if (candidates.reserve(n)){//compute residuals and select the pointsfor (unsigned i = 0; i < n; ++i){PointCoordinateType error = (*cloud->getPoint(i) - center).norm() - radius;if (error < maxResidual)candidates.addPointIndex(i);}candidates.resize(candidates.size());//eventually estimate the robust sphere parameters with least squares (iterative)if (RefineSphereLS(&candidates, center, radius)){//replace input cloud by this subset!cloud = &candidates;n = cloud->size();}}else{//not enough memory!//we'll keep the rough estimate...}}//update residuals{double residuals = 0;for (unsigned i = 0; i < n; ++i){const CCVector3* P = cloud->getPoint(i);double e = (*P - center).norm() - radius;residuals += e*e;}rms = sqrt(residuals/n);}return NoError;
}

4.相关代码

[1]C++实现:PCL RANSAC拟合空间3D球体
[2]python实现:Open3D——RANSAC三维点云球面拟合
[3] Open3D 最小二乘拟合球
[4] Open3D 非线性最小二乘拟合球

相关文章:

CloudCompare——拟合空间球

目录 1.拟合球2.软件操作3.算法源码4.相关代码 本文由CSDN点云侠原创&#xff0c;CloudCompare——拟合空间球&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫与GPT生成的文章。 1.拟合球 源码里用到了四点定球&#xff0c;…...

哪个牌子的护眼台灯适合学生?2024护眼台灯推荐

不知道各位父母对孩子的视力健康有没有关注&#xff0c;我国儿童青少年的近视率高达52.7%&#xff0c;也就是说&#xff0c;平均是个儿童中就有五个儿童存在视力问题&#xff0c;而且近视发生年龄提前至3到7岁。作为一名眼部护理博主&#xff0c;孩子从小看书、看屏幕起&#x…...

适用于动态 IT 环境的服务器流量监控软件

服务器在网络性能中起着至关重要的作用&#xff0c;这意味着保持其最佳容量至关重要。企业需要将 AI、ML 和云技术融入其 IT 中&#xff0c;从而提供充分的敏捷性、安全性和灵活性&#xff0c;在这方面&#xff0c;服务器流量监控已成为当务之急。通过定期监控通信、跟踪流量上…...

Java的Jar包和War包

在Java中&#xff0c;JAR&#xff08;Java Archive&#xff09;和WAR&#xff08;Web Archive&#xff09;都是用于打包和分发Java应用程序的压缩文件格式。它们在不同的应用场景中使用&#xff1a; JAR&#xff08;Java Archive&#xff09;&#xff1a; 用途&#xff1a; 主要…...

第二十一章 javascript数据代理(数据劫持)

文章目录 一、数据劫持对象的访问器属性 二、Object.defineProperty()三、Proxy()四、补充1. Object类新增方法2. Array类新增方法 一、数据劫持 数据劫持&#xff1a;能够拦截到数据被使用或被修改的时机&#xff0c;在这个时机除了可以获取数据的值或对数据的值进行修改之外…...

苹果电脑RAW图像处理软件Capture One Pro 22 mac软件介绍

Capture One Pro 22 for mac是一款专业的RAW文件转换器和图像编辑软件&#xff0c;拥有更新的处理引擎、市场领先的性能和强大的新功能&#xff0c;可为 500 多台高端相机提供具有美丽色彩和令人难以置信的细节的终极图像质量。 Capture One Pro 22 for Mac版软件介绍 Capture…...

phpcms v9后台添加草稿箱功能

一、后台添加文章模板phpcms/modules/content/templates/content_add.tpl.php中94行增加”保存草稿“按钮&#xff1a; <div class"button"><input value"<?php echo L(save_draft);?>" type"submit" name"dosubmit_draf…...

机器人持续学习基准LIBERO系列5——获取显示深度图

0.前置 机器人持续学习基准LIBERO系列1——基本介绍与安装测试机器人持续学习基准LIBERO系列2——路径与基准基本信息机器人持续学习基准LIBERO系列3——相机画面可视化及单步移动更新机器人持续学习基准LIBERO系列4——robosuite最基本demo 1.更改环境设置 LIBERO-master/l…...

Java 面试题 - 多线程并发篇

线程基础 创建线程有几种方式 继承Thread类 可以创建一个继承自Thread类的子类&#xff0c;并重写其run()方法来定义线程的行为。然后可以通过创建该子类的实例来启动线程。 示例代码&#xff1a; class MyThread extends Thread {public void run() {// 定义线程的行为} …...

2401d,讨论d串滑动参数

原文 因为对编译时执行的i串的兴趣,我一直在考虑搞个通用用例,而不是相关i串的用例. 滑动模板参数 请考虑以下模板: void pluto(string s)() {pragma(msg, s); } void test() {pluto!"hello"(); }因为s是编译时参数,这编译,而pragma(msg,s) 期望s为编译时值. voi…...

etcd官方docker镜像及dockerfile问题处理

解决下我之前etcd使用docker镜像启动的坑 1、问题镜像docker-file: 这个dockerfile看着看不出来问题,但如果有人真的执行我之前两篇文章的文件,就会有问题,什么问题呢,无法连接到etcd,由于我是刚装上docker,排查了一圈,包括docker网络及是否是本地docker的网络问题,…...

2023 IoTDB Summit:天谋科技高级开发工程师苏宇荣《汇其流:如何用 IoTDB 流处理框架玩转端边云融合》...

12 月 3 日&#xff0c;2023 IoTDB 用户大会在北京成功举行&#xff0c;收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题&#xff0c;多位学术泰斗、企业代表、开发者&#xff0c;深度分享了工业物联网时序数据库 IoTDB 的技术创新…...

Pygame程序的屏幕显示

不同对象的绘制与显示过程 在Pygame中&#xff0c;需要将所有需要在屏幕上显示的内容都绘制在一个display surface上。该Surface通常称为screen surface&#xff0c;它是pygame.display.set_mode()函数返回的Surface对象。 在绘制不同对象时&#xff0c;可以使用不同的绘制方…...

LVGL的List控件的触摸按键和实体按键的处理

在LVGL的List控件使用过程中&#xff0c;虽然通过触摸按键选择item&#xff0c;但是有些场景需要实体按键选取item&#xff0c;但是LVGL 的V8.3中没有像Emwin那样有函数选择list item的函数。LVGL中List引入了Group的概念&#xff0c;把列表项都添加到同一个group中。然后通过更…...

数据结构 模拟实现二叉树(孩子表示法)

目录 一、二叉树的简单概念 &#xff08;1&#xff09;关于树的一些概念 &#xff08;2&#xff09;二叉树的一些概念及性质 定义二叉树的代码&#xff1a; 二、二叉树的方法实现 &#xff08;1&#xff09;createTree &#xff08;2&#xff09;preOrder &#xff08;…...

Android14之解决刷机报错:Can not load Android system. Your data may be corrupt(一百七十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…...

二阶贝塞尔曲线生成弧线

概述 本文分享一个二阶贝塞尔曲线曲线生成弧线的算法。 效果 实现 1. 封装方法 class ArcLine {constructor(from, to, num 100) {this.from from;this.to to;this.num num;return this.getPointList();}getPointList() {const { from, to } thisconst ctrlPoint thi…...

FilterQuery过滤查询

ES中的查询操作分为两种&#xff1a;查询和过滤。查询即是之前提到的query查询&#xff0c;它默认会计算每个返回文档的得分&#xff0c;然后根据得分排序。而过滤只会筛选出符合条件的文档&#xff0c;并不计算得分&#xff0c;并且可以缓冲记录。所以我们在大范围筛选数据时&…...

java多线程(并发)夯实之路-线程池深入浅出

线程池 Thread Pool&#xff1a;线程池&#xff0c;存放可以重复使用的线程&#xff08;消费者&#xff09; Blocking Queue&#xff1a;阻塞队列&#xff0c;存放等待执行的任务&#xff08;生产者&#xff09; poll方法&#xff08;有时限地获取任务&#xff09;相对take注…...

数据库-列的类型-字符串char类型

char 和 varchar 类型 char 类型懂得都懂就是固定的字符串类型 char (maxLen) 例如 char(5) 这个长度为5 但插入数据‘a’时 是5 插入abc 也是5 即使插满固定 就像C/C语言里 char 字符数组一样 char str[64]; maxLen255 哈哈最多有255个字符多了我认为你是错误 varchar…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...