pclpy 最小二乘法拟合平面

pclpy 最小二乘法拟合平面

      • 一、算法原理
      • 二、代码
      • 三、结果
          • 1.左边原点云、右边最小二乘法拟合平面后点云投影
      • 四、相关数据

一、算法原理

平面方程的一般表达式为:
A x + B y + C z + D = 0 ( C ≠ 0 ) Ax + By + Cz + D = 0 \quad (C\neq0) Ax+By+Cz+D=0(C=0)
即:
Z = − A C x − B C y − D C Z = -\frac{A}{C}x-\frac{B}{C}y-\frac{D}{C} Z=CAxCByCD
记:
a 0 = − A C , a 1 = − B C , a 2 = − D C a_0 = -\frac{A}{C}, a_1 =-\frac{B}{C}, a_2=-\frac{D}{C} a0=CA,a1=CB,a2=CD
所以:
Z = a 0 x + a 1 y + a 2 Z = a_0x + a_1y + a_2 Z=a0x+a1y+a2
要用该 n 个点拟合平面方程,即使:
∑ n = 1 N ( a 0 x + a 1 y + a 2 ) 2 − > m i n \sum_{n=1}^{N}{(a_0x + a_1y + a_2)^2}->min n=1N(a0x+a1y+a2)2>min
要使S最小,对a,b,c求偏导

在这里插入图片描述

改写成矩阵的形式为:

在这里插入图片描述

二、代码

from pclpy import pcl
import numpy as np


def CloudShow(cloud1, cloud2):
    """
    Args:在一个窗口可视化多个点云
        cloud1: 点云数据1
        cloud2: 点云数据2
    """
    viewer = pcl.visualization.PCLVisualizer("viewer")  # 建立可刷窗口对象 窗口名 viewer
    v0 = 1  # 设置标签名(0, 1标记第一个窗口)
    viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v0)  # 创建一个可视化的窗口
    viewer.setBackgroundColor(0.0, 0.0, 0.0, v0)  # 设置窗口背景为黑色
    single_color = pcl.visualization.PointCloudColorHandlerCustom.PointXYZ(cloud1, 255.0, 0, 0.0)  # 将点云设置为红色
    viewer.addPointCloud(cloud1,  # 要添加到窗口的点云数据。
                         single_color,  # 指定点云的颜色
                         "sample cloud1",  # 添加的点云命名
                         v0)  # 点云添加到的视图

    v1 = 2  # 设置标签名(2代表第二个窗口)
    viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v1)  # 创建一个可视化的窗口
    viewer.setBackgroundColor(255.0, 255.0, 255.0, v1)  # 设置窗口背景为白色
    single_color = pcl.visualization.PointCloudColorHandlerCustom.PointXYZ(cloud2, 0.0, 255.0, 0.0)  # 将点云设置为绿色
    viewer.addPointCloud(cloud2,  # 要添加到窗口的点云数据。
                         single_color,  # 指定点云的颜色
                         "sample cloud2",  # 添加的点云命名
                         v1)  # 点云添加到的视图

    # 设置点云窗口(可移除对点云可视化没有影响)
    viewer.setPointCloudRenderingProperties(0,  # 设置点云点的大小
                                            1,  # 点云像素
                                            "sample cloud1",  # 识别特定点云
                                            v0)  # 在那个窗口可视化
    viewer.setPointCloudRenderingProperties(0,  # 设置点云点的大小
                                            1,  # 点云像素
                                            "sample cloud2",  # 识别特定点云
                                            v1)  # 在那个窗口可视化
    # viewer.addCoordinateSystem(1.0)  # 设置坐标轴 坐标轴的长度为1.0
    # 窗口建立
    while not viewer.wasStopped():
        viewer.spinOnce(10)


def plane(cloud, normal_vector):
    coeffs = pcl.ModelCoefficients()  # 创建了一个模型系数对象
    coeffs.values.append(normal_vector[0])  # a = 0.0
    coeffs.values.append(normal_vector[1])  # b = 0.0
    coeffs.values.append(normal_vector[2])  # c = 1.0
    coeffs.values.append(normal_vector[3])  # d = 0.0

    # 创建滤波器
    proj = pcl.filters.ProjectInliers.PointXYZ()  # 过滤器对象 proj,用于将点云投影到一个模型上。
    proj.setModelType(0)  # 模型类型被设为 0,代表使用平面模型。
    proj.setInputCloud(cloud)  # 将cloud点云数据进行处理
    proj.setModelCoefficients(coeffs)  # 处理参数coeffs
    cloud_projected = pcl.PointCloud.PointXYZ()  # 建立保存点云
    proj.filter(cloud_projected)  # 将投影结果保存

    return cloud_projected

if __name__ == '__main__':
    cloud1 = pcl.PointCloud.PointXYZ()
    reader = pcl.io.PCDReader()  # 设置读取对象
    reader.read('res/bunny.pcd', cloud1)  # 读取点云保存在cloud中

    # 调用函数,生成离散点
    x, y, z = cloud1.x, cloud1.y, cloud1.z
    N =  cloud1.size()
    # ------------------------构建系数矩阵-----------------------------
    A = np.array([[sum(x ** 2), sum(x * y), sum(x)],
                  [sum(x * y), sum(y ** 2), sum(y)],
                  [sum(x), sum(y), N]])

    B = np.array([[sum(x * z), sum(y * z), sum(z)]])

    # 求解
    X = np.linalg.solve(A, B.T)
    print('平面拟合结果为:z = %.3f * x + %.3f * y + %.3f' % (X[0], X[1], X[2]))
    a, b, c, d = X[0], X[1], -1, X[2]
    plane_cloud = plane(cloud1, [a, b, c, d])  # 获得投影后的点云数据

    # ------------------ 可视化点云 -----------------
    CloudShow(cloud1, plane_cloud) 

三、结果

1.左边原点云、右边最小二乘法拟合平面后点云投影

在这里插入图片描述

四、相关数据

最小二乘法拟合参考链接:最小二乘拟合平面(python/C++版) - 知乎 (zhihu.com)

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

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

相关文章

【深度学习笔记】3_14 正向传播、反向传播和计算图

3.14 正向传播、反向传播和计算图 前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中,我们只提供了模型的正向传播(forward propagation)的计算,即对输入计算模型输出,然后通过autograd模块来调…

Nest.js权限管理系统开发(五)返回格式化

返回格式化拦截器 在上一篇《Nest.js权限管理系统开发(四)Swagger API接入》中,我们在base.controller.ts中创建了多个接口,每个接口都有不同的返回类型。现实中我们往往需要统一返回数据的格式,例如: {&…

【零基础】VOSviewer小白入门第一课

官网安装:VOSviewer - Visualizing scientific landscapes 安装完成后即可以打开VOSviewer: 在 wos of science 中搜索关键词:lawdata 选择导出,按照plain text file格式导出,可以到处1000个。选择all record 得到下图 读取vosvi…

Linux安装jdk、tomcat、MySQL离线安装与启动

一、JDK和Tomcat的安装 1.JDK安装 直接上传到Linux服务器的,上传jdk、tomcat安装包 解压JDK安装包 //解压jdk tar -zxvf jdk-8u151-linux-x64.tar.gz 置环境变量(JAVA_HOME和PATH) vim /etc/profile 在文件末尾添加以下内容: //java environment expo…

设计模式学习笔记 - 面向对象 - 8.实践:贫血模型和充血模型的原理及实践

1.Web开发常用的贫血MVC架构违背OOP吗? 前面我们依据讲过了面向对象四大特性、接口和抽象类、面向对象和面向过程编程风格,基于接口而非实现编程和多用组合少用继承设计思想。接下来,通过实战来学习如何将这些理论应用到实际的开发中。 大部…

WiFi又演进了,这次是WiFi 7

现在很多笔记本laptop、电视TV、手机Phone,甚至车机IVI都有了WiFi和蓝牙BT的接入功能。 不管WiFi、蓝牙BlueTooth、NBIoT、ZigBee等等无线的技术、无线通信模块的技术,其本质都是在无线频谱上以某种频段某种调制方式传输某个协议的数据进行通信,所以通信标准的演进就决定着…

Linux之vim的使用详细解析

个人主页:点我进入主页 专栏分类:C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂 目录 一.vim简介 二.vim的基本概念 三.vim的基本操作 3.1准备 …

Kafka:kafka的主从模式和故障切换 ②

一、Kafka整体架构图 二、Kafka原题回答 Kafka集群有主从模式吗? Kafka集群实际上并没有严格意义上的主从模式。Kafka的设计是基于分布式的,每个Topic都会切分为多个Partition,每个Partition都有一个Leader和多个Follower。 所有的读写操作…

计算机网络面经-TCP的拥塞控制

写在前边 前边我们分享了网络分层协议、TCP 三次握手、TCP 四次分手。今天我们继续深入分享一下 TCP 中的拥塞控制。 对于 TCP 的拥塞控制,里边设计到很多细节,平平无奇的羊希望通过这一节能够将这部分内容串通起来,能够让你更深刻的记忆这部分内容。 思维导图 1、什么…

AIGC专栏9——Scalable Diffusion Models with Transformers (DiT)结构解析

AIGC专栏9——Scalable Diffusion Models with Transformers (DiT)结构解析 学习前言源码下载地址网络构建一、什么是Diffusion Transformer (DiT)二、DiT的组成三、生成流程1、采样流程a、生成初始噪声b、对噪声进行N次采样c、单次采样解析I、预测噪声I…

Spring的另一大的特征:AOP

目录 AOP (Aspect Oriented Programming)AOP 入门案例(注解版)AOP 工作流程——代理AOP切入点表达式AOP 通知类型AOP通知获取数据获取切入点方法的参数获取切入点方法返回值获取切入点方法运行异常信息 百度网盘分享链接输入密码数…

【Linux基础】Linux自动化构建工具make/makefile

背景 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后…

性格正直的人适合什么职业?

有信仰,有责任,有骨气,有尊严,这应该是大多数人对正直的人的理解,他们的心中有信仰,肩上有责任,灵魂有骨气,头上有尊严,不管在什么时候都能够坚守道德准则,不…

【文生视频】Diffusion Transformer:OpenAI Sora 原理、Stable Diffusion 3 同源技术

文生视频 Diffusion Transformer:Sora 核心架构、Stable Diffusion 3 同源技术 提出背景变换器的引入Diffusion Transformer (DiT)架构Diffusion Transformer (DiT)总结 OpenAI Sora 设计思路阶段1: 数据准备和预处理阶段2: 架构设计阶段3: 输入数据的结构化阶段4: …

蓝桥杯算法赛 第 6 场 小白入门赛 解题报告 | 珂学家 | 简单场 + 元宵节日快乐

前言 整体评价 因为适逢元宵节,所以这场以娱乐为主。 A. 元宵节快乐 题型: 签到 节日快乐,出题人也说出来自己的心愿, 祝大家AK快乐! import java.util.Scanner;public class Main {public static void main(String[] args) {System.out.println(&qu…

信息抽取(UIE):使用自然语言处理技术提升证券投资决策效率

一、引言 在当今快速变化的证券市场中,信息的价值不言而喻。作为一名资深项目经理,我曾领导一个关键项目,旨在通过先进的信息抽取技术,从海量的文本数据中提取关键事件,如企业并购、新产品发布以及政策环境的变动。这些…

学会字符转换

字符转换 题目描述:解法思路:解法代码:运行结果: 题目描述: 输入⼀一个字符串,将字符串中大写字母全部转为小写字母,小写字母转成大写字母,其他字符保持不变。注:字符串…

typescript使用解构传参

看下面这个函数 interface Student {id: number;name: string;class: string;sex: string;}function matriculation(student: Student) {//...}我们要调用它,就需要传递一个实现了Student约束的对象进去 interface Student {id: number;name: string;class: string;sex: string…

音视频数字化(数字与模拟-电视)

上一篇文章【音视频数字化(数字与模拟-音频广播)】谈了音频的广播,这次我们聊电视系统,这是音频+视频的采集、传输、接收系统,相对比较复杂。 音频系统的广播是将声音转为电信号,再调制后发射出去,利用“共振”原理,收音机接收后解调,将音频信号还原再推动扬声器,我…

Liunx--nginx负载均衡--前后端分离项目部署

一.nginx简介 Nginx是一个高性能的HTTP和反向代理服务器,它以其轻量级、占用资源少、并发能力强而广受欢迎。 详细介绍 开发背景与特点:Nginx由俄罗斯人Igor Sysoev开发,它是一个自由的、开源的软件。Nginx设计上注重性能和效率,能…