计算机视觉 | 基于 PointNet 网络的飞机零件 3D 点云分割

目录

  • 一、简要介绍
  • 二、环境设置
    • 2.1 实验配置
    • 2.2 必要库安装
  • 三、数据集解析
    • 3.1 数据集加载
    • 3.2 数据文件夹结构
    • 3.3 点云数据可视化
    • 3.4 数据获取与预处理
    • 3.5 数据集定义
  • 四、模型组网
    • 4.1 PointNet 介绍
    • 4.2 Paddle模型组网
    • 4.3 模型概要
  • 五、模型训练
  • 六、模型预测
  • 七、总结

Hi,大家好,我是半亩花海。 本项目从点云数据的分析出发,利用 Paddle 框架PointNet 网络,实现从数据集构建、模型组网到训练、预测全流程开发,实现对飞机零件的点云数据的三维点云分割任务。

一、简要介绍

点云是一种不同于图片的数据存储结构,其特有的无序性,使其在利用深度网络处理时,需要进行特殊的处理。常见的处理方法有将点云处理成体素后,以某种方式将体素转换为图片后进行处理,但这种方法往往伴随着计算量大等缺点。PointNet 模型能够有效处理点云分类、零件分割和语义解析等任务,展示了在处理非结构化数据时的优越性和灵活性。点云分割是根据空间、几何和纹理等特征对点云进行划分,使得同一划分内的点云拥有相似的特征。

二、环境设置

2.1 实验配置

由于深度学习对 GPU 要求较高,本文采用高配置的 “AutoDL 算力云” 云服务器,使用 PaddlePaddle 2.4.0 作为深度学习框架进行飞机零件的3D点云分割,实验配置如下表所示。

项目参数
GPURTX 4090D(24GB) * 1
CPU16 vCPU Intel® Xeon® Platinum 8481C
显存80GB
硬盘系统盘:30 GB;数据盘:50GB(免费)
操作系统Ubuntu 18.04
开发语言Python 3.8
深度学习框架PaddlePaddle 2.4.0
CUDA11.2

2.2 必要库安装

import os
import tqdm
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore", module="matplotlib")  # 忽略matplotlib的警告
from mpl_toolkits.mplot3d import Axes3D  # 导入3D绘图工具包# 导入Paddle相关库
import paddle
from paddle.io import Dataset
import paddle.nn.functional as F
from paddle.nn import Conv2D, MaxPool2D, Linear, BatchNorm, Dropout, ReLU, Softmax, Sequential# 查看Paddle版本
print('本项目使用paddle版本:{}'.format(paddle.__version__))

在这里插入图片描述

三、数据集解析

3.1 数据集加载

ShapeNet 数据集是一项持续的工作,旨在建立一个带有丰富注释的大规模 3D 形状数据集。形状网核心是完整形状网数据集的子集,具有干净的单个 3D 模型和手动验证的类别和对齐注释。它涵盖了 55 个常见的对象类别,约有 51,300 个独特的 3D 模型。

对于此示例,我们使用 PASCAL 3D+ 的 12 个对象类别之一,以飞机零件的分割为例,该类别作为 ShapenetCore 数据集的一部分包含在内。完整的数据集下载地址:https://shapenet.cs.stanford.edu/iccv17/ 。

3.2 数据文件夹结构

构建该数据集,PointNet 文件夹的结构如下:

PointNet/
├── dataset/
│   ├── shapenet/
│       ├── train_data/
│           ├── Airplane/
│               ├── 000043.pts(example)
│       ├── train_label/
│           ├── Airplane/
│               ├── 000043.seg(example)
├── output/
│   ├── PointNet_{}.pdparams
│   └── PointNet_{}.pdopt
└── 21142604.ipynb

3.3 点云数据可视化

点云数据的获取方式,一般都是使用深度相机或者雷达,其存储的形式一般为一个(N,4)的向量,其中,N 代表着这次采集的点云数量,4 代表着其中每个点在三维的坐标 x,y,z 和反射强度 r,但在本次的数据集中,点云的存储方式为(N,3),即不包括点云的反射强度 r。而 label 的存储方式则是为一个N维的向量,代表每个点具体的类别。

下面,我们通过读取点云的数据 data 和其标签 label,对我们需要处理的数据,有一个大致的认识。

# 可视化使用的颜色和对应label的名字
COLORS = [' ', 'b', 'r', 'g', 'pink']
label_map = ['', 'body', 'wing', 'tail', 'engine']# 定义可视化函数
def visualize_data(point_cloud, label, title):# 创建数据框架用于存储点云数据和对应的标签df = pd.DataFrame(data={"x": point_cloud[:, 0],"y": point_cloud[:, 1],"z": point_cloud[:, 2],"label": label,})# 创建3D图形对象fig = plt.figure(figsize=(15, 10))ax = plt.axes(projection="3d")# 散点图绘制所有点云数据ax.scatter(df["x"], df["y"], df["z"])# 根据标签绘制不同颜色的点for i in range(label.min(), label.max() + 1):c_df = df[df['label'] == i]ax.scatter(c_df["x"], c_df["y"], c_df["z"], label=label_map[i], alpha=0.5, c=COLORS[i])ax.legend()  # 添加图例plt.title(title)# 设置图形标题plt.show()# 显示图形# 定义点云和标签文件路径
show_point_cloud_path = 'dataset/shapenet/train_data/Airplane/000043.pts'
show_label_path = 'dataset/shapenet/train_label/Airplane/000043.seg'# 读取点云文件
point_cloud = np.loadtxt(show_point_cloud_path)
label = np.loadtxt(show_label_path).astype('int')  # 读取标签文件并转换为整数类型
visualize_data(point_cloud, label, 'label')  # 可视化点云数据# 打印点云和标签的形状
print('point cloud shape:{}'.format(point_cloud.shape))
print('label shape:{}'.format(label.shape))

在这里插入图片描述

3.4 数据获取与预处理

根据上面的可视化分析,我们可以知道,每个数据中点云 N 的数量是不同的,这不利于我们进行后续的处理,所以这里对数据集中的点云进行了随机采样,使每个点云的数量一致,此外,我们也将点云的坐标进行了正则化操作,最后将处理好的点云存储在内存中,方便后续 dataset 的构建。

此数据集中不仅包含 Airplane 类别,还包括 Bag,Cap,Car, Chair 类别,我们可以修改数据集和标签路径(data_path 和 label_path),进而对其他类别数据集进行使用。

# 定义数据和标签路径
data_path = 'dataset/shapenet/train_data/Airplane'
label_path = 'dataset/shapenet/train_label/Airplane'
# 采样点
NUM_SAMPLE_POINTS = 1024 
# 存储点云与label
point_clouds = []
point_clouds_labels = []# 获取数据目录下的所有文件名
file_list = os.listdir(data_path)
for file_name in tqdm.tqdm(file_list):# 获取label和data的地址label_name = file_name.replace('.pts', '.seg')point_cloud_file_path = os.path.join(data_path, file_name)label_file_path = os.path.join(label_path, label_name)# 读取label和datapoint_cloud = np.loadtxt(point_cloud_file_path)label = np.loadtxt(label_file_path).astype('int')# 如果点云数据少于需要采样的点,则直接去除if len(point_cloud) < NUM_SAMPLE_POINTS:continue# 获取点云数据的点数num_points = len(point_cloud)# 随机选择采样的索引sampled_indices = random.sample(list(range(num_points)), NUM_SAMPLE_POINTS)# 根据采样索引获取采样后的点云数据和标签数据sampled_point_cloud = np.array([point_cloud[i] for i in sampled_indices])sampled_label_cloud = np.array([label[i] for i in sampled_indices])# 正则化处理,去中心化并归一化norm_point_cloud = sampled_point_cloud - np.mean(sampled_point_cloud, axis=0)norm_point_cloud /= np.max(np.linalg.norm(norm_point_cloud, axis=1))# 存储采样后的点云数据和标签数据point_clouds.append(norm_point_cloud)point_clouds_labels.append(sampled_label_cloud)

在这里插入图片描述

# 可视化第一个采样后的点云数据和标签
visualize_data(point_clouds[0], point_clouds_labels[0], 'label')

3.5 数据集定义

在 Paddle 中,数据集的定义需完成以下四步:

  • paddle.io.Dataset 的继承
  • 构造函数的实现,主要完成一些初始化
  • __gtitem__方法的实现,即定义 index 时,可以返回对应的单条数据,包括训练数据和对应的标签
  • __len__方法的实现,即获取数据的大小

此外,这里还对数据集进行了训练集和验证集的划分,划分比例为验证集占总体的 20% ,并将定义好的数据集,通过 paddle.io.DataLoader 进行迭代器的封装,方便训练过程数据的读取操作。

class MyDataset(Dataset):# 步骤一:继承paddle.io.Dataset类def __init__(self, data, label):# 步骤二:实现构造函数,定义数据集大小super(MyDataset, self).__init__()self.data = dataself.label = labeldef __getitem__(self, index):# 步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)data = self.data[index]# 减1是因为原始label中是从1开始算类别数的label = self.label[index] - 1# 将数据重塑为(1, 1024, 3)的形状data = np.reshape(data, (1, 1024, 3))return data, labeldef __len__(self):# 步骤四:实现__len__方法,返回数据集总数目return len(self.data)# 数据集划分
VAL_SPLIT = 0.2
split_index = int(len(point_clouds) * (1 - VAL_SPLIT))# 划分训练集和验证集
train_point_clouds = point_clouds[:split_index]
train_label_cloud = point_clouds_labels[:split_index]
val_point_clouds = point_clouds[split_index:]
val_label_cloud = point_clouds_labels[split_index:]# 打印训练集和验证集的大小
print("Num train point clouds:", len(train_point_clouds))
print("Num train point cloud labels:", len(train_label_cloud))
print("Num val point clouds:", len(val_point_clouds))
print("Num val point cloud labels:", len(val_label_cloud))# 测试定义的数据集
train_dataset = MyDataset(train_point_clouds, train_label_cloud)
val_dataset = MyDataset(val_point_clouds, val_label_cloud)print('=============custom dataset test=============')
# 测试一个数据点的形状
for data, label in train_dataset:print('data shape:{} \nlabel shape:{}'.format(data.shape, label.shape))break# 定义批处理大小
BATCH_SIZE = 64
# 数据加载器
train_loader = paddle.io.DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
val_loader = paddle.io.DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False)

在这里插入图片描述

四、模型组网

4.1 PointNet 介绍

1. 点云数据的特点

PointNet 网络的设计主要是解决以下三个问题:

  • 点云的无序性 对称函数(symmetry function)的应用,如加法、乘法和取最大值函数等,在 PointNet 则是采用了 maxpooling(最大值汇聚)的方法。
  • 点云的交互性 在分割网络的分支里,可以看到其将某一层的信息和经过 maxpooling 得到的全局信息进行 concate 来达到全局和局部信息的交互。
  • 点云的变换不变性 在点云中,不论怎么旋转应该都不会改变其属性。在此前有人设计变换矩阵,以数据增强的方法来解决这个问题。而这里直接将这个变换矩阵的学习也融入到网络中,设计了 input transform 结构。

2. PointNet 基本出发点

由于点的无序性,需要模型具有置换不变性。

f ( x 1 , x 2 , … , x n ) ≡ f ( x π 1 , x π 2 , … , x π n ) , x i ∈ R D f\left(x_1, x_2, \ldots, x_n\right) \equiv f\left(x_{\pi_1}, x_{\pi_2}, \ldots, x_{\pi_n}\right), \quad x_i \in \mathbb{R}^D f(x1,x2,,xn)f(xπ1,xπ2,,xπn),xiRD

那么可以使用下列公式来体现:

f ( x 1 , x 2 , … , x n ) = max ⁡ { x 1 , x 2 , … , x n } f\left(x_1, x_2, \ldots, x_n\right)=\max \left\{x_1, x_2, \ldots, x_n\right\} f(x1,x2,,xn)=max{x1,x2,,xn}

f ( x 1 , x 2 , … , x n ) = x 1 + x 2 + … + x n f\left(x_1, x_2, \ldots, x_n\right)=x_1+x_2+\ldots+x_n f(x1,x2,,xn)=x1+x2++xn

求 max 值与位置没有关系,使用加法也是与位置无关。那么我们就直接使用 Max 函数:

但是这样会导致我们的特征太少,损失太多。那么如何解决?我们可以先升维然后再做 Max 操作(其实就是神经网络的隐层)

f ( x 1 , x 2 , … , x n ) = γ ∘ g ( h ( x 1 ) , … , h ( x n ) ) f\left(x_1, x_2, \ldots, x_n\right)=\gamma \circ g\left(h\left(x_1\right), \ldots, h\left(x_n\right)\right) f(x1,x2,,xn)=γg(h(x1),,h(xn))

上面提及到了升维这个东西,神经网络本质就是一个特征提取器,下面的 MLP 可以理解为一个感知机,可以为全连接层、卷积等等,把它上升为一个高维特征,再经过 max 函数得到全局再进行输出。

3. PointNet 算法网络架构

网络有三个关键模块:

  • 最大池化层(作为聚合所有点信息的对称函数
  • 局部和全局信息组合结构
  • 两个对齐输入点和点特征的联合对齐网络

例如,对于无序输入的对称函数(Symmetry Function for Unordered Input)来说:

为了使模型对输入置换保持不变,我们的方法是通过对点集中的变换元素使用一个对称函数来近似定义点集中的一般函数。

f ( { x 1 , … , x n } ) ≈ g ( h ( x 1 ) , … , h ( x n ) ) f\left(\left\{x_1, \ldots, x_n\right\}\right) \approx g\left(h\left(x_1\right), \ldots, h\left(x_n\right)\right) f({x1,,xn})g(h(x1),,h(xn))

其中,h 采用多层感知机(MLP),g 采用一个单变量函数和最大池化函数的组合。通过 h 的集合,可以学习许多 f 来捕获集合的不同属性。

4.2 Paddle模型组网

基于 PaddlePaddle 框架组建 PointNet 网络,整个网络包含输入变换网络、MLP、特征变换网络和分割网络等模块。其组网过程与 torch 无大致区别,继承 nn.Layer 后,重写前向传播 forward 方法。

其中代码中的网络定义,对应网络细节如下:

  • input_transform_net+input_fc: 对应 T-Net,后续 reshape 到 3x3 做为变换矩阵和输入进行变换。
  • mlp: 对应升维的 MLP 层,均使用了 1x1 的卷积层。
  • seg_net: 对应 Segmentation Network 中一系列的 MLP 层。
class PointNet(paddle.nn.Layer):def __init__(self, name_scope='PointNet_', num_classes=4, num_point=1024):super(PointNet, self).__init__()self.num_point = num_point# 输入变换网络self.input_transform_net = Sequential(Conv2D(1, 64, (1, 3)),BatchNorm(64),ReLU(),Conv2D(64, 128, (1, 1)),BatchNorm(128),ReLU(),Conv2D(128, 1024, (1, 1)),BatchNorm(1024),ReLU(),MaxPool2D((num_point, 1)))# 输入变换的全连接层self.input_fc = Sequential(Linear(1024, 512),ReLU(),Linear(512, 256),ReLU(),Linear(256, 9, weight_attr=paddle.framework.ParamAttr(initializer=paddle.nn.initializer.Assign(paddle.zeros((256, 9)))),bias_attr=paddle.framework.ParamAttr(initializer=paddle.nn.initializer.Assign(paddle.reshape(paddle.eye(3), [-1])))))# MLP 第一部分self.mlp_1 = Sequential(Conv2D(1, 64, (1, 3)),BatchNorm(64),ReLU(),Conv2D(64, 64,(1, 1)),BatchNorm(64),ReLU(),)# 特征变换网络self.feature_transform_net = Sequential(Conv2D(64, 64, (1, 1)),BatchNorm(64),ReLU(),Conv2D(64, 128, (1, 1)),BatchNorm(128),ReLU(),Conv2D(128, 1024, (1, 1)),BatchNorm(1024),ReLU(),MaxPool2D((num_point, 1)))# 特征变换的全连接层self.feature_fc = Sequential(Linear(1024, 512),ReLU(),Linear(512, 256),ReLU(),Linear(256, 64*64))# MLP 第二部分self.mlp_2 = Sequential(Conv2D(64, 64, (1, 1)),BatchNorm(64),ReLU(),Conv2D(64, 128,(1, 1)),BatchNorm(128),ReLU(),Conv2D(128, 1024,(1, 1)),BatchNorm(1024),ReLU(),)# 最后的分割网络self.seg_net = Sequential(Conv2D(1088, 512, (1, 1)),BatchNorm(512),ReLU(),Conv2D(512, 256, (1, 1)),BatchNorm(256),ReLU(),Conv2D(256, 128, (1, 1)),BatchNorm(128),ReLU(),Conv2D(128, 128, (1, 1)),BatchNorm(128),ReLU(),Conv2D(128, num_classes, (1, 1)),Softmax(axis=1))def forward(self, inputs):batchsize = inputs.shape[0]# 输入变换网络前向传播t_net = self.input_transform_net(inputs)t_net = paddle.squeeze(t_net)t_net = self.input_fc(t_net)t_net = paddle.reshape(t_net, [batchsize, 3, 3])# 将输入点云数据变换x = paddle.reshape(inputs, shape=(batchsize, 1024, 3))x = paddle.matmul(x, t_net)x = paddle.unsqueeze(x, axis=1)x = self.mlp_1(x)# 特征变换网络前向传播t_net = self.feature_transform_net(x)t_net = paddle.squeeze(t_net)t_net = self.feature_fc(t_net)t_net = paddle.reshape(t_net, [batchsize, 64, 64])# 将特征数据变换x = paddle.reshape(x, shape=(batchsize, 64, 1024))x = paddle.transpose(x, (0, 2, 1))x = paddle.matmul(x, t_net)x = paddle.transpose(x, (0, 2, 1))x = paddle.unsqueeze(x, axis=-1)point_feat = xx = self.mlp_2(x)x = paddle.max(x, axis=2)# 扩展全局特征并与点特征拼接global_feat_expand = paddle.tile(paddle.unsqueeze(x, axis=1), [1, self.num_point, 1, 1])x = paddle.concat([point_feat, global_feat_expand], axis=1)# 最后的分割网络前向传播x = self.seg_net(x)x = paddle.squeeze(x, axis=-1)x = paddle.transpose(x, (0, 2, 1))return x

4.3 模型概要

# 创建 PointNet 模型实例
pointnet = PointNet()# 打印模型摘要信息
paddle.summary(pointnet, (64, 1, 1024, 3))  # 第一个参数是模型实例,第二个参数是输入数据的形状

五、模型训练

模型训练中使用的参数如下:

  • 优化器:Adam,其中 weight_decay=0.001
  • 损失函数:CrossEntropyLoss
  • 训练轮数:epoch_num=100
  • 保存轮数:save_interval=2
  • 验证轮数:val_interval=2
  • 最佳准确率初始化:best_acc = 0
  • 模型保存地址:output_dir=’./output’
# 创建模型
model = PointNet()
model.train()# 优化器定义
optim = paddle.optimizer.Adam(parameters=model.parameters(), weight_decay=0.001)
# 损失函数定义
loss_fn = paddle.nn.CrossEntropyLoss()
# 评价指标定义
m = paddle.metric.Accuracy()# 参数设定
epoch_num = 100  # 训练轮数
save_interval = 2  # 每多少个epoch保存
val_interval = 2  # 每多少个epoch验证
best_acc = 0  # 最佳准确率初始化# 模型保存地址
output_dir = './output'
if not os.path.exists(output_dir):os.makedirs(output_dir)# 训练过程
plot_acc = []
plot_loss = []
for epoch in range(1, epoch_num + 1):  # 从1开始计数,到epoch_num结束total_loss = 0for batch_id, data in enumerate(train_loader()):inputs = paddle.to_tensor(data[0], dtype='float32')  # 转换输入数据类型labels = paddle.to_tensor(data[1], dtype='int64')    # 转换标签数据类型predicts = model(inputs)  # 前向传播,获得预测结果# 计算损失和反向传播loss = loss_fn(predicts, labels)total_loss += loss.numpy()[0]loss.backward()# 计算accpredicts = paddle.reshape(predicts, (predicts.shape[0]*predicts.shape[1], -1))labels = paddle.reshape(labels, (labels.shape[0]*labels.shape[1], 1))correct = m.compute(predicts, labels)m.update(correct)# 优化器更新optim.step()optim.clear_grad()avg_loss = total_loss / (batch_id + 1)  # 平均损失plot_loss.append(avg_loss)print("epoch: {}/{}, loss is: {}, acc is:{}".format(epoch, epoch_num, avg_loss, m.accumulate()))m.reset()# 保存if epoch % save_interval == 0:model_name = str(epoch)paddle.save(model.state_dict(), './output/PointNet_{}.pdparams'.format(model_name))paddle.save(optim.state_dict(), './output/PointNet_{}.pdopt'.format(model_name))# 训练中途验证if epoch % val_interval == 0:model.eval()  # 切换到验证模式for batch_id, data in enumerate(val_loader()): inputs = paddle.to_tensor(data[0], dtype='float32')  # 转换输入数据类型labels = paddle.to_tensor(data[1], dtype='int64')    # 转换标签数据类型predicts = model(inputs)  # 前向传播,获得预测结果predicts = paddle.reshape(predicts, (predicts.shape[0] * predicts.shape[1], -1))labels = paddle.reshape(labels, (labels.shape[0] * labels.shape[1], 1))correct = m.compute(predicts, labels)m.update(correct)val_acc = m.accumulate()plot_acc.append(val_acc)if val_acc > best_acc:best_acc = val_accprint("===================================val===========================================")print('val best epoch in:{}, best acc:{}'.format(epoch, best_acc))print("===================================train===========================================")# 保存最佳模型paddle.save(model.state_dict(), './output/best_model.pdparams')paddle.save(optim.state_dict(), './output/best_model.pdopt')m.reset()model.train()  # 切换回训练模式

将训练结果可视化,如下代码所示。

# 可视化模型训练过程
def plot_result(item, title):plt.figure()plt.xlabel("Epochs")plt.plot(item)plt.title(title, fontsize=14)plt.grid()plt.show()# 绘制验证集准确率变化图和训练损失变化图
plot_result(plot_acc, 'val acc')
plot_result(plot_loss, 'training loss')

由上述结果可知,验证集准确率稳定在 80%-90%最高达到 91.45%,而训练集损失率随着训练世代的增加而越来越低,说明本实验中 PointNet 模型的训练效果良好。

六、模型预测

通过模型预测结果可知,飞机零件被不同颜色的点云进行良好分割,并且预测(pred)与标签(label)结果几乎一样,说明预测结果很好,模型的架构效果良好。

# 指定最佳模型参数的路径
ckpt_path = 'output/best_model.pdparams'# 加载网络和参数
para_state_dict = paddle.load(ckpt_path)
model = PointNet()
model.set_state_dict(para_state_dict)
model.eval()# 加载数据集中的点云数据
point_cloud = point_clouds[0]
show_point_cloud = point_cloud  # 用于可视化的原始点云数据
point_cloud = paddle.to_tensor(np.reshape(point_cloud, (1, 1, 1024, 3)), dtype='float32')  # 转换为Tensor并增加batch维度
label = point_clouds_labels[0]# 前向推理获取预测结果
preds = model(point_cloud)
show_pred = paddle.argmax(preds, axis=-1).numpy() + 1  # 转换为numpy数组,并将预测结果从0开始编号调整为从1开始
# 可视化预测结果和真实标签
visualize_data(show_point_cloud, show_pred[0], 'pred')
visualize_data(show_point_cloud, label, 'label')

七、总结

本项目从点云数据的分析出发,利用 Paddle 框架,实现了数据集构建、模型组网、训练和预测的全流程开发。项目主要针对飞机零件的 3D 点云数据,进行精确的 part segmentation 任务。通过 PointNet 分类网络,模型能够有效地理解和处理点云数据中的空间信息,实现对飞机零件的细致分割。该项目不仅包括数据预处理和增强,还涉及模型优化和超参数调整,从而提升分割精度和效率,具有重要的工程应用价值和研究意义。

尽管如此,项目也存在一些不足:数据集规模和多样性有限,限制了模型的泛化能力。3D 点云数据处理和模型训练需要大量计算资源,对硬件配置要求较高。此外,PointNet 模型复杂性较高,导致其可解释性不足。点云数据易受噪声和缺失点影响,降低了模型处理低质量数据的能力,同时实时处理能力也有待提高。

未来可以通过扩大数据集规模和多样性、优化计算资源使用、提升模型可解释性、增强鲁棒性和抗噪性以及引入并行计算等技术,进一步提升模型的精度和效率。同时,将模型应用于汽车零件、建筑构件和医疗器械等其他需要精细分割的领域,扩展项目的应用范围和影响力。通过这些改进,项目将在点云数据处理领域贡献更多创新和实践经验。

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

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

相关文章

2.1 程序设计语言基础

程序设计语言概述 常见的编程语言 编译和解释 程序设计语言的基本成分 数据成分、运算成分、控制成分、传输成分 函数 传值调用、传址调用 编译程序基本原理

window上部署sql server改动端口、和sqlserver的一些还原、批量插入存储过程的命令

1.端口的查看和启动 --windows上安装上sql server数据库后&#xff0c;搜索界面搜索sql&#xff0c;会出现配置管理器&#xff0c;点击进入 --进入后再次选择配置管理器 2. sqlserver数据库还原图形化 sqlserver还原数据库时会使数据库进入一个restore的还原状态&#xff0c;…

昇思25天学习打卡营第6天|Vision Transformer

文章目录 昇思MindSpore应用实践基于MindSpore的Vision Transformer1、Vision Transformer&#xff08;ViT&#xff09;简介网络结构 2、Attention模块Encoder部分用到的功能函数&#xff1a;整体构建ViT模型 3、模型训练4、模型验证 Reference 昇思MindSpore应用实践 本系列文…

linux网络命令:httpie详解-简单易用的命令行 HTTP 客户端

目录 一、命令概述 二、基本特点 1、直观和友好的命令语句 2、内置 JSON 支持 3、支持多种请求方法 4、支持 HTTPS、代理和授权验证 5、支持多种请求数据格式 6、自定义 headers 头 7、持久 sessions 存储 8、插件支持 三、安装 1、对于基于 Debian 的系统&#xf…

MQ运行时遇到的问题

遇到的问题描述&#xff1a;我在绑定通道的时候发现了通道绑定失败&#xff0c; 原因&#xff1a; 在代码中我第一次创建交换机的时候类型的默认没有修改成topic类型的&#xff0c;导致后面的代码再去进行注册的时候并没有实现那个类型 解决&#xff1a; 更改代码&#xff0…

vue3+ el-upload封装上传组件

组件功能介绍 上传格式限制上传大小限制上传文件数量限制自定义上传区上传成功回调禁用上传开关与点击上传自定义事件暴露所以上传文件列表&#xff08;uploadList&#xff09;与当前文件数据&#xff08;uploadLatestFile&#xff09; 组件代码Upload.vue <template>&l…

在Stimulsoft 报告中连接来自 MySQL 的数据

Stimulsoft Ultimate &#xff08;原Stimulsoft Reports.Ultimate&#xff09;是用于创建报表和仪表板的通用工具集。该产品包括用于WinForms、ASP.NET、.NET Core、JavaScript、WPF、PHP、Java和其他环境的完整工具集。无需比较产品功能&#xff0c;Stimulsoft Ultimate包含了…

Firewalld 防火墙基础

Firewalld 防火墙基础 一、Firewalld概述firewalld 简介firewalld 和 iptables 的关系firewalld 与 iptables service 的区别 二、Firewalld 网络区域区域介绍Firewalld数据处理流程 三、Firewalld 防火墙的配置方法firewall-config 图形工具“区域”选项卡“服务”选项卡改变防…

仓库管理系统24--统计报表

原创不易&#xff0c;打字不易&#xff0c;截图不易&#xff0c;多多点赞&#xff0c;送人玫瑰&#xff0c;留有余香&#xff0c;财务自由明日实现 1、引用LiveCharts 2、创建LiveChartViewModel using GalaSoft.MvvmLight; using LiveCharts.Wpf; using LiveCharts; using Sy…

从新手到高手:Scala函数式编程完全指南,Scala 数据类型(4)

1、Scala 数据类型 Scala 与 Java有着相同的数据类型&#xff0c;下表列出了 Scala 支持的数据类型&#xff1a;

ros1仿真导航机器人 navigation

仅为学习记录和一些自己的思考&#xff0c;不具有参考意义。 1navigation导航框架 2导航设置过程 &#xff08;1&#xff09;启动仿真环境 roslaunch why_simulation why_robocup.launch &#xff08;2&#xff09;启动move_base导航、amcl定位 roslaunch why_simulation nav…

无偏归一化自适应心电ECG信号降噪方法(MATLAB)

心电信号作为一种生物信号&#xff0c;含有大量的临床应用价值的信息&#xff0c;在现代生命医学研究中占有重要的地位。但心电信号低频、低幅值的特点&#xff0c;使其在采集和传输的过程中经常受到噪声的干扰&#xff0c;使心电波形严重失真&#xff0c;从而影响后续的病情分…

你还不会买智能猫砂盆吗?跟你们详细讲解今年最火的智能猫砂盆!

智能猫砂盆的坑&#xff0c;想必有很多养猫家庭都踩过吧。自己买回来的机器&#xff0c;不是空间不够大&#xff0c;导致猫咪拉到外面去&#xff0c;就是铲不干净&#xff0c;还得自己进行二次清理&#xff0c;搞得这个智能猫砂盆白买了。那如果我们想要购买合适自己家猫咪的智…

数据链路层分析

文章目录 前言一、数据链路层概述二、终端之间的通信三、帧格式1.Ethernet_II型2.IEEE 802.3 四、MTU分析五、数据帧的传输1.MAC地址2.单播3.广播4.组播5.数据帧的收发 前言 网络中传输数据需要定义并遵循一些标准&#xff0c;以太网是根据IEEE802.3标准来管理和控制数据帧的&…

sqlserver开启CDC

1、背景 由于需要学习flink cdc&#xff0c;并且数据选择sqlserver&#xff0c;所以这里记录sqlserver的cdc开启操作步骤。 2、基础前提 官方介绍地址&#xff1a;https://learn.microsoft.com/zh-cn/sql/relational-databases/track-changes/enable-and-disable-change-dat…

如何优化前端性能:提高网页加载速度的实用技巧

我们在前端开发中&#xff0c;性能优化是提高用户体验的关键因素。网页加载速度直接影响用户的满意度和留存率。本文将介绍几种优化前端性能的实用方法&#xff0c;帮助你提高网页加载速度。 问题描述 &#xff1a; 首先前端性能优化涉及多个方面&#xff0c;包括减少HTTP请…

专为运维工程师设计!阿里藏经阁出品的Python实战手册被我搞来了

Python 可能是极少数既简单又强大的编程语言中的一种。更重要的是&#xff0c;用它来编程是非常快乐的事。 今天给小伙伴们分享的是阿里“藏经阁”出品的专门给运维工程师设计的Python实战手册 废话不多说&#xff0c;下面把内容展示给大家 01 Python快速回顾 02 Python脚本…

【大模型】基于ChatGLM进行微调及应用 [更新中......]

文章目录 一、前言二、说明2.1 代码结构2.2 依赖包版本 三、启动对话演示3.1 命令行交互 cli_demo.py3.2 网页交互 web_demo.py 四、微调模型4.1 基于 P-Tuning v2 微调模型4.1.1 软件依赖4.1.2 下载数据集4.1.3 下载模型文件4.1.4 操作步骤 4.2 基于 Full Parameter 微调模型4…

从进程到协程,浅谈Java提高CPU利用率的发展

综合CPU利用率来讲,计算机远古时期,为提高CPU利用率,有以下概念 串行进程->并行进程->线程->线程池>->虚拟线程(协程) 一,串行进程, 早期的操作系统对任务调度,往往从最简单的实现开端,串型进程意思是对分配的一个任务,其任务能百分百占用CPU,哪怕…

前程无忧滑块

声明(lianxi a15018601872) 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 前言(lianxi …