计算机视觉|3D 点云处理黑科技:PointNet++ 原理剖析与实战指南
一、引言
在当今数字化与智能化快速发展的时代,3D 点云处理技术在多个前沿领域中发挥着重要作用。特别是在自动驾驶和机器人视觉等领域,这项技术已成为实现智能化的关键支撑。
以自动驾驶为例,车辆需要实时感知周围复杂的环境信息,包括行人、车辆、交通标志和路况等。3D 点云数据能够提供高精度的三维空间信息,使自动驾驶车辆更准确地识别和定位周围物体,从而做出安全、合理的行驶决策。在城市街道上,自动驾驶车辆通过 3D 点云处理技术,可以清晰地感知周围环境,有效应对复杂路况,提高行车的安全性和效率。
在机器人视觉领域,3D 点云处理技术同样至关重要。机器人在执行任务时,需要对周围环境进行精确感知和理解,以完成物体抓取、导航避障等操作。3D 点云数据为机器人提供了详细的环境信息,使其能够准确感知物体的形状、位置和姿态,从而实现更智能的操作。例如,在工业生产线上,机器人利用 3D 点云处理技术,可以快速、准确地抓取目标物体,提升生产效率和质量。
在 3D 点云处理的技术中,PointNet++ 是一种性能出色的 3D 卷积网络,受到广泛关注。它在处理 3D 点云数据时表现出色,为解决相关难题提供了有效方案。接下来,我们将深入探讨 PointNet++ 的工作原理及其在 3D 点云处理领域的应用。
二、PointNet++ 诞生背景
(一)3D 点云数据特点与挑战
3D 点云数据是由大量离散的三维坐标点组成的集合,这些点能够准确表示物体或场景的三维几何形状。在自动驾驶中,通过激光雷达获取的周围环境的 3D 点云数据,可以帮助车辆感知周围物体的位置和形状,从而支持行驶决策。但 3D 点云数据具有一些特殊性质,这些性质给传统机器学习和深度学习方法带来了挑战。
-
3D 点云数据具有无序性。与图像数据中像素点按固定行列顺序排列不同,点云数据中的点没有固定的排列顺序。例如,同一个物体的点云,无论点的顺序如何调整,其代表的形状和语义信息保持不变。这使得传统基于有序数据的处理方法,如卷积神经网络(CNN),难以直接应用于点云数据。因为 CNN 的卷积操作依赖数据的局部空间结构和顺序,而无序的点云数据无法满足这一条件。
-
3D 点云数据还具有稀疏性。点云数据是对三维空间的离散采样,某些区域可能点较多,而其他区域点很少甚至没有点。在室内场景扫描中,由于家具或墙壁的遮挡,部分角落或遮挡区域可能无法获取点云数据。这种稀疏性导致数据分布不均匀,使得模型难以学习到全面的特征。传统深度学习方法在处理稀疏数据时效果较差,因为它们通常假设数据分布均匀。
-
此外,3D 点云数据是非结构化的。与图像数据的规则网格结构不同,点云数据中的点之间没有明确的连接关系和拓扑结构。这增加了提取点云数据局部特征和全局特征的难度。传统的图神经网络(GNN)虽然能处理非结构化数据,但在处理大规模点云数据时,由于计算复杂度高,效率较低。
(二)PointNet 的局限性
在 PointNet++ 出现之前,PointNet 是一种创新的点云处理网络,首次实现了直接处理 3D 点云数据,无需将其转换为体素或多视图图像等其他格式。它通过对称函数和最大池化操作,解决了点云数据的无序性问题,能够提取点云的全局特征,在 3D 形状分类和目标检测等任务中取得了一定成果。
然而,PointNet 存在一些局限性。它无法有效提取局部特征。在实际应用中,物体的局部特征对准确识别和理解物体至关重要。例如,在识别汽车时,轮子、车门等局部特征是判断其类别的重要依据。而 PointNet 仅对整个点云进行全局特征提取,忽略了点云数据中的局部结构信息,导致在处理复杂形状或需要精细分类的任务时,性能不足。
PointNet 对不同密度点云数据的适应性较差。由于点云数据的采集受多种因素影响,不同场景或设备采集到的点云数据密度可能差异较大。面对密度不一致的点云数据时,PointNet 难以学习到统一的特征表示,影响模型的泛化能力和准确性。
此外,PointNet 在处理大规模点云数据时,计算效率较低。随着点云数据规模增加,其计算量显著增大,这在对实时性要求较高的场景(如自动驾驶)中成为一个重要问题。这些局限性为 PointNet++ 的发展提供了动力,推动了 3D 点云处理技术的进一步研究和改进。
三、PointNet++ 原理剖析
(一)核心架构与设计理念
PointNet++ 采用层次化的特征学习架构,这是其与 PointNet 的主要区别。它通过在不同尺度上对局部区域进行特征提取和聚合,能够学习到点云数据的局部和全局特征。
其核心模块是 Set Abstraction(SA)模块,包含三个关键步骤:采样、分组和 PointNet 处理。
-
在采样阶段,通过特定算法从大量点云数据中选取代表性的点,这些点称为质心点,用于后续处理。这一步骤减少数据量,同时保留点云的关键结构信息。
-
分组阶段以质心点为中心,根据规则(如距离阈值或固定数量的最近邻点),将周围的点划分为不同组,每组代表一个局部区域。这样,整个点云数据被分割成多个局部区域,每个区域包含一定范围内的点云信息。
-
在每个分组内,PointNet++ 使用 PointNet 对局部区域的点云进行特征学习。PointNet 提取每个局部区域的特征,并通过对称函数(如最大池化)将这些局部特征聚合为一个全局特征,生成每个质心点的特征表示。
通过多次迭代应用 Set Abstraction 模块,PointNet++ 能够学习到多级别特征,从局部细微特征过渡到全局宏观特征。这种层次化设计使模型能够捕捉点云数据中不同尺度的几何结构信息,并在处理过程中保持旋转不变性和置换不变性。无论点云数据如何旋转或点的顺序如何变化,模型都能提取一致的特征。
(二)关键技术解析
1、采样策略:最远点采样(FPS)算法
在 PointNet++ 中,采样策略用于从大量点云数据中选取代表性的点,最远点采样(FPS)算法是实现这一目标的关键技术。FPS 算法基于贪心策略,每次选择距离已采样点最远的点作为下一个采样点,确保采样点在点云空间中分布均匀,保留关键信息。
具体过程如下:
- 对于包含 N 个点的点云集合,首先随机选择一个初始采样点。
- 然后,计算其余点到该点的欧氏距离,选择距离最远的点作为第二个采样点。
- 接着,对于每个未采样点,计算其到已采样点集合的最小距离,从中选择最小距离最大的点作为下一个采样点。
- 重复此过程,直到达到预定采样点数。
例如,在表示建筑物的点云数据中,FPS 算法可选择角落、边缘等关键位置的点作为采样点,代表整体形状和结构。与随机采样相比,FPS 避免采样点过于集中,降低计算量并提高模型对不同形状点云的适应性。
2、分组操作:Ball Query 方法
分组操作是 PointNet++ 中获取局部区域点云的重要步骤,Ball Query 方法是常用手段。该方法以采样点为中心,根据设定的半径和点数进行分组。具体过程为:以每个采样点为球心,以半径 r r r 画球,在球内选取距离球心最近的 K K K 个点(若点数不足 K K K,则全选),这些点与采样点构成一个局部区域。
例如,在一个点云数据集中,若设定半径为 0.5 米、点数为 32,则以采样点为中心,在半径 0.5 米的球形区域内选取最近的 32 个点。每个采样点对应一个局部区域,捕捉点云的局部几何结构信息,为后续特征提取提供基础。
3、特征学习:PointNet 在每个分组内的应用
完成采样和分组后,PointNet++ 在每个分组内利用 PointNet 进行特征学习。PointNet 直接处理点云数据,通过多层感知机(MLP)将局部点云的坐标及其他特征(如颜色、法向量)映射到高维空间,提取更有表达能力的特征。
例如,在表示汽车点云的分组中,PointNet 输入三维坐标和颜色信息,经过 MLP 的多层变换,输出高维特征向量,包含局部区域的几何形状和颜色分布信息。然后,通过最大池化等对称函数,将分组内所有点的特征聚合为一个全局特征向量,代表该局部区域的特征。这为多尺度特征融合和全局特征提取奠定基础。
4、多尺度特征融合:MSG(多尺度分组)和 MRG(多分辨率分组)方法
点云数据密度差异给特征提取带来挑战,PointNet++ 提出 MSG(多尺度分组) 和 MRG(多分辨率分组) 方法,实现多尺度特征融合,提升对复杂场景的适应性。
-
MSG 方法在同一采样点上使用不同半径进行分组,分别提取特征并融合。例如,对一个采样点,以半径 r1、r2、r3 进行 Ball Query 分组,得到三个尺度的局部区域,利用 PointNet 提取特征后,将三个特征向量拼接,形成包含多尺度信息的特征向量。这使模型能同时捕捉不同尺度特征,适应密度不均匀的点云数据。
-
MRG 方法从不同分辨率角度分组。先将点云划分为高、中、低分辨率子集,在各子集上进行分组和特征提取,最后融合特征。高分辨率子集点多,捕捉细微特征;低分辨率子集点少,提供宏观结构信息。通过融合不同分辨率特征,模型充分利用点云信息,提升复杂场景理解能力。
(三)与其他 3D 卷积网络对比优势
与常见的 3D 卷积网络相比,PointNet++ 具有多项优势。特别是在计算效率、特征提取能力以及处理不规则数据的适应性方面,确实展现了PointNet++的独特优势。
-
计算效率 :PointNet++避免了传统3D CNN中需要将点云数据转换为体素网格的过程,因此在内存消耗和计算资源方面具有明显优势。尤其在自动驾驶场景中,需要实时处理大量点云数据时,PointNet++能够显著提升计算效率,确保车辆能够迅速作出决策。
-
特征提取能力 :与传统的体素化CNN不同,PointNet++通过其层次化特征学习架构,能够捕捉到点云数据的局部和全局特征。这对于具有复杂几何形状和不规则结构的物体尤其重要,因为传统的体素化处理往往会丢失细节,而PointNet++能保留并精准提取这些细节,提升分类和分割精度。
-
适应性与鲁棒性 :PointNet++通过特殊的采样、分组以及特征学习方法,有效应对点云数据中的无序性和稀疏性。在实际应用中,点云数据的密度不均、噪声以及不规则性常常影响结果,PointNet++的设计使其能够提高对这些挑战的适应性,增强模型的鲁棒性和泛化能力。
从这几点来看,PointNet++在处理大规模和复杂点云数据时显得更加高效和精确。你有什么想法或想进一步深入探讨的地方吗?
四、PointNet++ 应用领域
(一)应用领域与案例展示
PointNet++ 凭借其强大的点云处理能力,在多个领域展现出重要价值。
1. 自动驾驶领域
在自动驾驶中,障碍物检测和场景感知是关键任务。例如,特斯拉的自动驾驶系统利用 PointNet++ 处理激光雷达获取的点云数据。通过实时分析周围环境,PointNet++ 能准确识别车辆、行人、交通标志等障碍物,并估计其位置、速度和运动方向。在复杂的城市道路中,PointNet++ 快速识别潜在危险目标,为自动驾驶决策提供支持,有效避免碰撞,确保行车安全。
2. 机器人视觉领域
在机器人视觉中,物体识别和抓取是任务基础。尤其在工业生产线上,机器人需识别不同形状和材质的零部件,进行抓取与组装。借助 PointNet++,机器人分析零部件的点云数据,提取独特特征,实现精确识别和定位。面对多种零部件时,PointNet++ 判断其类别和姿态,引导机器人准确抓取目标,提升生产效率和产品质量。
3. 虚拟现实领域
在虚拟现实(VR)中,场景重建是核心技术之一。通过 PointNet++ 处理现实场景的点云数据,可以快速、准确地重建三维场景模型。例如,在虚拟旅游应用中,PointNet++ 处理景区的点云数据后,生成真实的三维场景,用户通过头戴设备浏览世界各地的名胜古迹,实现自由探索。
五、代码实战
下面以 PyTorch 框架为例,展示 PointNet++ 的基本代码实现,包括模型搭建、训练和测试过程,同时会介绍实践中数据预处理、超参数调整、模型评估等要点。
(一)模型搭建
首先,需要导入必要的库,如torch
、torch.nn
等。然后,根据 PointNet++ 的原理,定义关键的函数和模块,如最远点采样(FPS)、球形邻域查询(Ball Query)、Set Abstraction(SA)模块和 Feature Propagation(FP)模块等。
import torch
import torch.nn as nn
import torch.nn.functional as Fdef squaredistance(src, dst):B, N, = src.shape_, M, = dst.shapedist = -2 * torch.matmul(src, dst.permute(0,2,1))dist += torch.sum(src**2,-1).view(B,N,1)dist += torch.sum(dst**2,-1).view(B,1,M)return distdef farthestpointsample(xyz, npoint):device = xyz.deviceB, N, C = xyz.shapecentroids = torch.zeros(B,npoint,dtype=torch.long).to(device)distance = torch.ones(B,N).to(device)*1e10farthest = torch.randint(0,N,(B,),dtype=torch.long).to(device)batchindices = torch.arange(B,dtype=torch.long).to(device)for i in range(npoint):centroids[:,i] = farthestcentroid = xyz[batchindices,farthest,:].view(B,1,3)dist = torch.sum((xyz-centroid)**2,-1)mask = dist < distancedistance[mask] = dist[mask]farthest = torch.max(distance,-1)[1]return centroidsdef indexpoints(points, idx):device = points.deviceB = points.shape[0]viewshape = list(idx.shape)viewshape[1:] = [1]*(len(viewshape)-1)repeatshape = list(idx.shape)repeatshape[0] = 1batchindices = torch.arange(B,dtype=torch.long).to(device).view(viewshape).repeat(repeatshape)return points[batchindices,idx:]def queryballpoint(radius, nsample, xyz, newxyz):device = xyz.deviceB, N, C = xyz.shape_, S, _ = newxyz.shapegroupidx = torch.arange(N,dtype=torch.long).view(1,1,N).repeat([B,S,1])sqrdists = squaredistance(newxyz, xyz)groupidx[sqrdists > radius**2] = Ngroupidx = groupidx.sort(dim=-1)[0][:,:,:nsample]groupfirst = groupidx[:, :,0].view(B,S,1).repeat([1,1,nsample])mask = groupidx == Ngroupidx[mask] = groupfirst[mask]return groupidxclass PointNetSetAbstraction(nn.Module):def __init__(self, npoint, radius, nsample, inchannel, mlp):super().__init__()self.npoint = npointself.radius = radiusself.nsample = nsamplelayers = []lastchannel = inchannel +3for outchannel in mlp:layers.append(nn.Conv2d(lastchannel,outchannel,1))layers.append(nn.BatchNorm2d(outchannel))layers.append(nn.ReLU())lastchannel = outchannelself.mlp = nn.Sequential(*layers)def forward(self, xyz, points):B, N, C = xyz.shapeS = self.npointfpsidx = farthestpointsample(xyz, S)newxyz = indexpoints(xyz, fpsidx)idx = queryballpoint(self.radius, self.nsample, xyz, newxyz)groupedxyz = indexpoints(xyz, idx) - newxyz.unsqueeze(-2)if points is not None:groupedpoints = indexpoints(points, idx)groupedpoints = torch.cat([groupedxyz, groupedpoints], dim=-1)else:groupedpoints = groupedxyzgroupedpoints = groupedpoints.permute(0,3,2,1)newpoints = self.mlp(groupedpoints)newpoints = torch.max(newpoints,3)[0]return newxyz, newpointsclass PointNetFeaturePropagation(nn.Module):def __init__(self, inchannel, mlp):super().__init__()layers = []lastchannel = inchannelfor outchannel in mlp:layers.append(nn.Conv1d(lastchannel,outchannel,1))layers.append(nn.BatchNorm1d(outchannel))layers.append(nn.ReLU())lastchannel = outchannelself.mlp = nn.Sequential(*layers)def forward(self, xyz1, xyz2, points1, points2):if xyz1 is None:return self.mlp(points2)dists = squaredistance(xyz1, xyz2)dists, idx = dists.sort(dim=-1)dists, idx = dists[:, :, :3], idx[:, :, :3]distrecip = 1.0/(dists +1e-8)norm = torch.sum(distrecip,dim=2,keepdim=True)weight = distrecip/norminterpolatedpoints = torch.sum(indexpoints(points2,idx)*weight.view(B,-1,3,1),dim=2)if points1 is not None:newpoints = torch.cat([points1,interpolatedpoints],dim=1)else:newpoints = interpolatedpointsnewpoints = newpoints.unsqueeze(-1)newpoints = self.mlp(newpoints)newpoints = newpoints.squeeze(-1)return newpointsclass PointNet2Cls(nn.Module):def __init__(self, numclasses):super().__init__()self.sa1 = PointNetSetAbstraction(npoint=512,radius=0.2,nsample=32,inchannel=3,mlp=[64,64,128])self.sa2 = PointNetSetAbstraction(npoint=128,radius=0.4,nsample=64,inchannel=128+3,mlp=[128,128,256])self.sa3 = PointNetSetAbstraction(npoint=None,radius=None,nsample=None,inchannel=256+3,mlp=[256,512,1024])self.fc1 = nn.Linear(1024,512)self.bn1 = nn.BatchNorm1d(512)self.drop1 = nn.Dropout(0.4)self.fc2 = nn.Linear(512,256)self.bn2 = nn.BatchNorm1d(256)self.drop2 = nn.Dropout(0.4)self.fc3 = nn.Linear(256,numclasses)def forward(self, xyz):xyz = xyz.permute(0,2,1)l1xyz, l1points = self.sa1(xyz, None)l2xyz, l2points = self.sa2(l1xyz, l1points)l3xyz, l3points = self.sa3(l2xyz, l2points)x = l3points.view(-1,1024)x = self.drop1(F.relu(self.bn1(self.fc1(x))))x = self.drop2(F.relu(self.bn2(self.fc2(x))))x = self.fc3(x)return x
(二)数据预处理
在训练模型之前,需要对数据进行预处理。这包括数据的读取、归一化、划分训练集和测试集等步骤。以常见的 ModelNet40 数据集为例,数据集中每个样本是一个包含三维坐标的点云文件。
import os
import numpy as np
import torch.utils.data as dataclass ModelNet40(data.Dataset):def __init__(self, root, split='train', numpoints=1024, transform=None):self.root = rootself.split = splitself.numpoints = numpointsself.transform = transformself.data = []self.label = []self.catfile = os.path.join(self.root, 'modelnet40shapenames.txt')self.cat = [line.rstrip() for line in open(self.catfile)]self.classes = dict(zip(self.cat, range(len(self.cat))))for i in self.cat:for fn in os.listdir(os.path.join(self.root, i)):if split == 'train' and int(fn[8:-4]) % 10 != 0:self.data.append(os.path.join(self.root, i, fn))self.label.append(self.classes[i])elif split == 'test' and int(fn[8:-4]) % 10 == 0:self.data.append(os.path.join(self.root, i, fn))self.label.append(self.classes[i])def __getitem__(self, index):pointset = np.loadtxt(self.data[index], delimiter=',').astype(np.float32)label = self.label[index]pointset = pointset[:, 0:3]choice = np.random.choice(len(pointset), self.numpoints, replace=True)pointset = pointset[choice, :]pointset -= np.expanddims(np.mean(pointset, axis=0), 0)dist = np.max(np.sqrt(np.sum(pointset**2, axis=1)), 0)pointset /= distif self.transform is not None:pointset = self.transform(pointset)pointset = torch.fromnumpy(pointset).float()label = torch.fromnumpy(np.array([label])).long()return pointset, labeldef __len__(self):return len(self.data)
(三)训练过程
定义好模型和数据预处理函数后,就可以进行模型的训练了。在训练过程中,需要设置损失函数(如交叉熵损失函数)、优化器(如 Adam 优化器),并迭代训练多个 epoch。
import os
import numpy as np
import torch
import torch.nn as nn
import torch.utils.data as data# 定义设备
device = torch.device("cuda:0" if torch.cuda.isavailable() else "cpu")# 超参数设置
batchsize=32
numepochs=50
learningrate=0.001
numclasses=40# 加载数据集
traindataset = ModelNet40(root='data/modelnet40normalresampled', split='train')
trainloader = data.DataLoader(traindataset, batchsize=batchsize, shuffle=True, numworkers=4)
testdataset = ModelNet40(root='data/modelnet40normalresampled', split='test')
testloader = data.DataLoader(testdataset, batchsize=batchsize, shuffle=False, numworkers=4)# 初始化模型、损失函数和优化器
model = PointNet2Cls(numclasses).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learningrate)# 训练模型
for epoch in range(numepochs):model.train()runningloss = 0.0for i, (points, labels) in enumerate(trainloader):points, labels = points.to(device), labels.to(device)optimizer.zero_grad() # 修正:原代码中的zerograd应为zero_grad()outputs = model(points)loss = criterion(outputs, labels.squeeze())loss.backward()optimizer.step()runningloss += loss.item()print(f'Epoch{epoch+1}/{numepochs},Loss:{runningloss/len(trainloader)})')
(四)测试过程
训练完成后,需要对模型进行测试,评估其性能。可以使用准确率等指标来衡量模型的表现。
import torch# 测试模型
model.eval()
correct = 0
total = 0
with torch.no_grad(): # 修正:nograd→no_gradfor points, labels in testloader:points, labels = points.to(device), labels.to(device)outputs = model(points)_, predicted = torch.max(outputs, 1) # 移除.data(新版本PyTorch不需要)total += labels.size(0)correct += (predicted == labels).sum().item() # 移除可能多余的squeeze()
print(f'Accuracy:{100*correct/total:.1f}%') # 优化输出格式
(五)实践要点
1、数据预处理要点:
-
归一化:对输入点云数据进行归一化处理,将其缩放到一个合适的范围,如 [-1, 1] 或 [0, 1],有助于提高模型的收敛速度和稳定性。上述代码中,通过减去点云的均值并除以最大距离进行归一化。
-
数据增强:可以采用随机旋转、平移、缩放等数据增强方法,增加数据的多样性,防止模型过拟合。在实际应用中,可以根据具体任务和数据特点选择合适的数据增强策略。
2、超参数调整要点:
-
学习率:学习率是影响模型训练效果的重要超参数之一。如果学习率过大,模型可能无法收敛,甚至会发散;如果学习率过小,模型训练速度会非常缓慢。可以采用学习率衰减策略,如指数衰减或余弦退火,随着训练的进行逐渐降低学习率。
-
批大小:批大小决定了每次训练时输入模型的数据量。较大的批大小可以加快训练速度,但可能会占用更多的内存;较小的批大小可以减少内存需求,但可能会导致训练过程不稳定。需要根据硬件资源和数据集大小来选择合适的批大小。
-
采样点数和半径:在 Set Abstraction 模块中,采样点数(
npoint
)和半径(radius
)会影响模型对局部特征的提取能力。需要根据点云数据的密度和复杂程度来调整这些参数,以获得更好的特征表示。
3、模型评估要点:
-
准确率:准确率是最常用的评估指标之一,用于衡量模型预测正确的样本比例。在分类任务中,可以通过计算预测类别与真实类别的匹配程度来得到准确率。
-
召回率和 F1 值:对于类别不均衡的数据集,准确率可能无法全面反映模型的性能。此时,可以使用召回率和 F1 值等指标。召回率表示真实正样本中被正确预测的比例,F1 值是准确率和召回率的调和平均数,综合考虑了模型的准确性和召回能力。
-
混淆矩阵:混淆矩阵可以直观地展示模型在各个类别上的预测情况,包括正确预测和错误预测的数量。通过分析混淆矩阵,可以了解模型在哪些类别上表现较好,哪些类别上容易出错,从而有针对性地改进模型。
六、总结与展望
(一)PointNet++的特点与应用
PointNet++ 是一种用于3D点云处理的深度学习模型,通过其层次化架构和Set Abstraction模块,能够有效提取点云的局部和全局特征。这种设计使其在处理复杂3D场景时表现出色。
1、主要特点
- 高效特征提取:PointNet++通过层次化方式捕捉点云的细节和整体信息,适用于多样化场景。
- 多尺度特征融合:采用MSG(多尺度分组)和MRG(多分辨率分组)技术,整合不同尺度的特征,提升模型对噪声、遮挡和密度不均的适应性。
- 鲁棒性强:在数据缺失或不完整的情况下,仍能准确识别物体,适用于室内外复杂环境。
3、应用场景
- 自动驾驶:从激光雷达点云中提取车辆、行人、道路等目标特征,支持实时决策,确保安全。
- 室内场景理解:处理遮挡和数据不均的点云,识别物体,实现空间感知。
- 技术推动:为3D深度学习提供新思路,克服传统方法局限,启发后续研究。
(二)未来发展方向
PointNet++在技术融合与应用扩展方面具有显著优势。在技术融合方面,它可以与Transformer结合,利用Transformer处理长距离依赖的能力,提高大规模点云数据的分析效率;同时,与生成对抗网络(GAN)结合,通过GAN实现点云补全和生成,增强模型对缺失数据的处理能力。在应用扩展方面,PointNet++具有多种应用可能性。在医疗领域,它可以分析医学影像中的点云数据,辅助医生识别病变组织,提高诊断准确性。在文物保护领域,通过处理文物扫描的点云数据,PointNet++支持文物的数字化重建和修复,为文化遗产保护提供技术支持。在教育领域,利用点云数据创建3D教学场景,PointNet++能够提供沉浸式、互动式的学习体验,丰富教学手段。综上所述,PointNet++通过技术融合提升了点云处理能力,并凭借其灵活性在医疗、文物保护和教育等多个领域展现出广泛的应用前景,有望在未来发挥更大作用。
延伸阅读
-
AI Agent 系列文章
-
计算机视觉系列文章
-
机器学习核心算法系列文章
-
深度学习系列文章
相关文章:
计算机视觉|3D 点云处理黑科技:PointNet++ 原理剖析与实战指南
一、引言 在当今数字化与智能化快速发展的时代,3D 点云处理技术在多个前沿领域中发挥着重要作用。特别是在自动驾驶和机器人视觉等领域,这项技术已成为实现智能化的关键支撑。 以自动驾驶为例,车辆需要实时感知周围复杂的环境信息ÿ…...
【VUE2】第三期——样式冲突、组件通信、异步更新、自定义指令、插槽
目录 1 scoped解决样式冲突 2 data写法 3 组件通信 3.1 父子关系 3.1.1 父向子传值 props 3.1.2 子向父传值 $emit 3.2 非父子关系 3.2.1 event bus 事件总线 3.2.2 跨层级共享数据 provide&inject 4 props 4.1 介绍 4.2 props校验完整写法 5 v-model原理 …...
WebAssembly技术及应用了解
WebAssembly(Wasm)是一种为Web设计的高效、低级的二进制指令格式,旨在提升Web应用的性能并支持多种编程语言。以下是对其核心概念、优势、应用场景及开发流程的系统介绍: 1. 核心概念 二进制格式:Wasm采用紧凑的二进制…...
工程化与框架系列(26)--前端可视化开发
前端可视化开发 📊 引言 前端可视化是现代Web应用中不可或缺的一部分,它能够以直观的方式展示复杂的数据和信息。本文将深入探讨前端可视化开发的关键技术和最佳实践,包括图表绘制、数据处理、动画效果等方面。 可视化技术概述 前端可视化…...
ESP32的IDF开发学习-WiFi的开启、配置与连接
前言 本章节将实现如何使用ESP32的WiFi功能,尽可能的详细地介绍 简介 ESP32中的wifi支持双工作模式 Station(STA)模式:连接到路由器或其他AP设备,可通过esp_wifi_set_mode(WIFI_MODE_STA)设置。SoftAP模式…...
2025-3-9 一周总结
目前来看本学期上半程汇编语言,编译原理,数字电路和离散数学是相对重点的课程. 在汇编语言和编译原理这块,个人感觉黑书内知识点更多,细节更到位,体系更完整,可以在老师讲解之前进行预习 应当及时复习每天的内容.第一是看书,然后听课,在一天结束后保证自己的知识梳理完整,没有…...
【网络编程】事件选择模型
十、基于I/O模型的网络开发 10.9 事件选择模型 10.0.1 基本概念 事件选择(WSAEventSelect) 模型是另一个有用的异步 I/O 模型。和 WSAAsyncSelect 模 型类似的是,它也允许应用程序在一个或多个套接字上接收以事件为基础的网络事件通知,最 主要的差别在…...
Java核心语法:从变量到控制流
一、变量与数据类型(对比Python/C特性) 1. 变量声明三要素 // Java(强类型语言,需显式声明类型) int age 25; String name "CSDN"; // Python(动态类型) age 25 name …...
信息安全与网络安全的区别_信息安全与网络安全之差异探析
在当今数字化时代,信息安全与网络安全成为了人们关注的热点话题。尽管这两个概念经常被提及,但它们之间存在着明显的区别。本文旨在探讨信息安全与网络安全的定义、范畴及应对策略,以帮助读者更好地理解和应对相关挑战。 一、定义与范畴的差…...
http协议的三次握手机制
HTTP协议是基于TCP协议的,因此HTTP的三次握手机制实际上就是TCP的三次握手机制。TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。为了确保通信的可靠性,TCP在建立连接时需要进行三次握手。下面我们详细…...
探秘沃尔什-哈达玛变换(WHT)原理
沃尔什-哈达玛变换(WHT)起源 起源与命名(20世纪早期) 数学基础:该变换的理论基础由法国数学家雅克哈达玛(Jacques Hadamard)在1893年提出,其核心是哈达玛矩阵的构造。扩展与命名&…...
C++ Windows下屏幕截图
屏幕截图核心代码(如果要求高帧率,请使用DxGI): // RGB到YUV的转换公式 #define RGB_TO_Y(r, g, b) ((int)((0.299 * (r)) (0.587 * (g)) (0.114 * (b)))) #define RGB_TO_U(r, g, b) ((int)((-0.169 * (r)) - (0.331 * (g)) …...
【python爬虫】酷狗音乐爬取练习
注意:本次爬取的音乐仅有1分钟试听,仅作学习爬虫的原理,完整音乐需要自行下载客户端。 一、 初步分析 登陆酷狗音乐后随机选取一首歌,在请求里发现一段mp3文件,复制网址,确实是我们需要的url。 复制音频的…...
电路的一些设计经验
这个C37在这里位于AMS1117-3.3稳压器的输入端。这个是作为输入滤波电容,有助于平滑输入电压,减少输入电压的纹波和噪声,从而提高稳压器LDO的稳定性。 电容器储存电荷,当输入电压出现小的拨动或者纹波时,电容器可以释放…...
Windows编译环境搭建(MSYS2\MinGW\cmake)
我的音视频/流媒体开源项目(github) 一、基础环境搭建 1.1 MSYS2\MinGW 参考:1. 基于MSYS2的Mingw-w64 GCC搭建Windows下C开发环境_msys2使用mingw64编译 在Widndows系统上,使用gcc工具链(g)进行C程序开发?可以的&a…...
Vue 框架深度解析:源码分析与实现原理详解
文章目录 一、Vue 核心架构设计1.1 整体架构流程图1.2 模块职责划分 二、响应式系统源码解析2.1 核心类关系图2.2 核心源码分析2.2.1 数据劫持实现2.2.2 依赖收集过程 三、虚拟DOM与Diff算法实现3.1 Diff算法流程图3.2 核心Diff源码 四、模板编译全流程剖析4.1 编译流程图4.2 编…...
前端 | CORS 跨域问题解决
问题:Access to fetch at http://localhost:3000/save from origin http://localhost:5174 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the request…...
《白帽子讲 Web 安全》之文件操作安全
目录 引言 (一)文件上传与下载漏洞概述 1.文件上传的常见安全隐患 1.1前端校验的脆弱性与服务端脚本执行危机在文件上传流程中,部分开发者可能会在前端使用 JavaScript 代码对文件后缀名进行简单校验,试图以此阻止非法文件上传…...
【AI】AI开源IDE:CLine源码分析报告
1. 源码位置: CLine 是一个开源的 VSCode 插件,其完整源码托管在 GitHub 的 cline/cline 仓库中。这个仓库包含 CLine 的核心逻辑(TypeScript 编写),包括与 LLM 的对话控制、工具调用接口,以及 VSCode 插件…...
使用数据库和缓存的时候,是如何解决数据不一致的问题的?
1.缓存更新策略 1.1. 缓存旁路模式(Cache Aside) 在应用里负责管理缓存,读取时先查缓存,如果命中了则返回缓存,如果未命中就查询数据库,然后返回缓存,返回缓存的同时把数据给写入缓存中。更新…...
docker compose 以redis为例
常见docker compose 命令 》》注意这个是旧版本的,新版本 docker 与compose 之间没有 - 新版本的 docker compose 把 version 取消了 ,redis 默认是没有配置文件的 ,nginx,mysql 默认是有的 services:redis:image: redis:lat…...
基于Kubernetes部署MySQL主从集群
以下是一个基于Kubernetes部署MySQL主从集群的详细YAML示例,包含StatefulSet、Service、ConfigMap和Secret等关键配置。MySQL主从集群需要至少1个主节点和多个从节点,这里使用 StatefulSet 初始化脚本 实现主从自动配置。 1. 创建 Namespace (可选) ap…...
VMware中安装配置Ubuntu(2024最新版 超详细)
目录 一、安装虚拟机软件 二、VMware虚拟机 三、 Ubuntu 下载 (1)官网下载 (2)清华镜像网站下载 四、创建虚拟机 五、Ubuntu 系统安装过程的配置 六、更换国内镜像源 七、环境搭建完毕 全篇较长,请慢慢观看 一…...
【Linux】信号处理以及补充知识
目录 一、信号被处理的时机: 1、理解: 2、内核态与用户态: 1、概念: 2、重谈地址空间: 3、处理时机: 补充知识: 1、sigaction: 2、函数重入: 3、volatile&…...
如何在rust中解析 windows 的 lnk文件(快捷方式)
一、从标题二开始看😁 这些天在使用rust写一个pc端应用程序,需要解析lnk文件获取lnk的图标以及原程序地址,之前并没有过pc端应用程序开发的经验, 所以在广大的互联网上游荡了两天。额🥺 今天找到了这个库 lnk_parse很…...
大模型系列课程学习-基于Vllm/Ollama/Ktransformers完成Deepseek推理服务部署
1.机器配置及实验说明 基于前期搭建的双卡机器装机教程,配置如下: 硬件名称参数备注CPUE5-2680V42 *2(线程28个)无GPU2080TI-22G 双卡魔改卡系统WSL Unbuntu 22.04.5 LTS虚拟机 本轮实验目的:基于VLLM/Ollama/ktran…...
Unity Shader学习总结
1.帧缓冲区和颜色缓冲区区别 用于存储每帧每个像素颜色信息的缓冲区 帧缓冲区包括:颜色缓冲区 深度缓冲区 模板缓冲区 自定义缓冲区 2.ImageEffectShader是什么 后处理用的shader模版 3.computerShader 独立于渲染管线之外,在显卡上运行,大量…...
Java多线程与高并发专题——什么是阻塞队列?
引入 阻塞队列(Blocking Queue)是一种线程安全的队列数据结构,它的主要特点是: 线程安全:多个线程可以安全地同时访问队列。阻塞操作:当队列为空时,从队列中获取元素的操作会被阻塞࿰…...
【Recon】CTF Web类题目主要类型
CTF Web类题目主要类型 1. 信息搜集类2. 注入类漏洞3. 文件处理漏洞4. 身份验证与会话漏洞5. 服务端漏洞6. 客户端漏洞7. 代码审计与PHP特性8. 业务逻辑漏洞总结 CTF(Capture The Flag)竞赛中的Web类题目主要考察参赛者对Web应用漏洞的识别与利用能力&am…...
comfyui(python)下载insightface失败
使用comfyui时,安装插件zenid、instantid、ip-adapter等换脸插件时,因为依赖insightface安装失败,导致插件中的节点无法正常使用,需要单独安装insightface。 下载insightface到本地,下载地址 选择与自己python版本一致…...
《DataWorks 深度洞察:量子机器学习重塑深度学习架构,决胜复杂数据战场》
在数字化浪潮汹涌澎湃的当下,大数据已然成为推动各行业发展的核心动力。身处这一时代洪流,企业对数据的处理与分析能力,直接关乎其竞争力的高低。阿里巴巴的DataWorks作为大数据领域的扛鼎之作,凭借强大的数据处理与分析能力&…...
Docker小游戏 | 使用Docker部署DOS游戏合集
Docker小游戏 | 使用Docker部署DOS游戏合集 前言项目介绍项目简介项目预览二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署dos-games网页小游戏下载镜像创建容器检查容器状态检查服务端口检查容器日志安全设置四、访问DOS游戏网页五、进阶玩法下载游戏拷贝…...
【redis】慢查询分析与优化
慢查询指在Redis中执行时间超过预设阈值的命令,其日志记录是排查性能瓶颈的核心工具。Redis采用单线程模型,任何耗时操作都可能阻塞后续请求,导致整体性能下降。 命令的执行流程 根据Redis的核心机制,命令执行流程可分为以下步骤…...
ThinkPHP框架
在电脑C磁盘中安装composer 命令 在电脑的D盘中创建cd文件夹 切换磁盘 创建tp框架 创建一个aa的网站,更换路径到上一步下载的tp框架路径 在管理中修改路径 下载压缩包public和view 将前面代码中的public和view文件替换 在PHPStom 中打开文件 运行指定路径 修改demo…...
从零构建高可用MySQL自动化配置系统:核心技术、工具开发与企业级最佳实践
在现代企业级数据库管理中,手动配置 MySQL 已无法满足高效、稳定和可扩展的需求。本文从 MySQL 配置管理的核心原理 出发,深入剖析 自动化配置工具的架构设计、关键技术实现,并结合 企业级落地方案,帮助读者构建一套 高可用、智能化的 MySQL 自动化配置系统。无论是 DevOps…...
qt 播放pcm音频
一、获取PCM音频 ffmpeg -i input.mp3 -acodec pcm_s16le -ar 44100 -ac 2 -f s16le output.pcm -acodec pcm_s16le:指定16位小端PCM编码格式(兼容性最佳)-ar 44100:设置采样率为CD标准44.1kHz(可替换为16000/8000等&a…...
开启mysql远程登录
目录 前言开启步骤 前言 为了安全考虑,mysql默认不允许远程登录,需要我们自己开启。当然在远程登录之前mysql的端口也要开放。下面是mysql开启远程登录的步骤。 开启步骤 本地登录mysql mysql -u root -p然后输入登录密码 给登录账号授权 GRANT AL…...
中级网络工程师面试题参考示例(5)
企业园区网络设计 问题: 请描述一下如何设计一个企业园区网络,包括核心层、汇聚层和接入层的功能及其关键技术。 解答: 核心层:负责高速数据交换,通常使用高性能的三层交换机,支持高带宽和低延迟。关键技…...
【每日学点HarmonyOS Next知识】输入框自动获取焦点、JS桥实现方式、Popup设置全屏蒙版、鼠标事件适配、Web跨域
1、HarmonyOS TextInput或TextArea如何自动获取焦点? 可以使用 focusControl.requestFocus 对需要获取焦点的组件设置焦点,具体可以参考文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-attribut…...
Git学习笔记(二)
Git学习笔记(二) 下载VSCode创建本地仓库推送远程仓库界面功能 使用 VSCode 进行Git仓库的项目管理 这篇文章是我学完使用 命令行终端 管理Git仓库额外学习的 文章主要用于巩固和方便后续复习 下载VSCode 可以看我这篇文章下载VSCode 创建本地仓库 …...
UDP协议和报文格式
✍作者:柒烨带你飞 💪格言:生活的情况越艰难,我越感到自己更坚强;我这个人走得很慢,但我从不后退。 📜系列专栏:网络安全从菜鸟到飞鸟的逆袭 目录 一,UDP协议1࿰…...
Java TCP 通信:实现简单的 Echo 服务器与客户端
TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议。与 UDP 不同,TCP 保证了数据的顺序、可靠性和完整性,适用于需要可靠传输的应用场景,如文件传输、网页浏览等。本文将基于 Java 实现一个简单的…...
升级到Android Studio 2024.2.2 版本遇到的坑
一、上来就编译报错,大概率是因为选择了替换安装,本地配置文件出错 找到本地当前版本的配置文件,删掉,重启studio就好了: 1、打开终端 2、“cd /Users/用户名/Library/Application\ Support/Google” //到Google目录 …...
hom_mat2d_to_affine_par 的c#实现
hom_mat2d_to_affine_par 的c#实现 背景:为课室贡献一个通用函数,实现halcon算子的同等效果,查询csdn未果,deepseek二哥与chtgpt大哥给不了最终程序,在大哥与二哥帮助下,最终实现同等效果。 踩坑…...
#9 【code】实现扩散模型的一个jupyter notebook
今天以一个简单的notebook入手,学习一下扩散模型的运行流程。有点困难不要紧,一个人吃了六个馒头才饱,他是吃第一个饱的,还是第六个饱的呢?始终坚信,现在的技术积累,终会成为未来高楼大厦的根基! import torch import torchvision import matplotlib.pyplot as pltdef …...
三星首款三折叠手机被曝外屏6.49英寸:折叠屏领域的新突破
在智能手机的发展历程中,折叠屏手机的出现无疑是一次具有里程碑意义的创新。它打破了传统手机屏幕尺寸的限制,为用户带来了更加多元和便捷的使用体验。而三星,作为手机行业的巨头,一直以来都在折叠屏技术领域积极探索和创新。近日,三星首款三折叠手机的诸多细节被曝光,其…...
《OkHttp:工作原理 拦截器链深度解析》
目录 一、OKHttp 的基本使用 1. 添加依赖 2. 发起 HTTP 请求 3. 拦截器(Interceptor) 4. 高级配置 二、OKHttp 核心原理 1. 责任链模式(Interceptor Chain) 2. 连接池(ConnectionPool) 3. 请求调度…...
Python 中多种方式获取屏幕的 DPI值
在 Python 中,可以通过多种方式获取屏幕的 DPI(每英寸点数)。以下是几种常见的方法: 方法 1:使用 tkinter 模块 tkinter 是 Python 的标准 GUI 库,可以通过它获取屏幕的 DPI。 import tkinter as tkdef …...
linux安装Mariadb10.5并修改端口
首先配置yum源 进入下方的文件进行配置 vim /etc/yum.repos.d/MariaDB.repo填写下方内容 [mariadb]name MariaDBbaseurl https:///mirrors.aliyun.com/mariadb/yum/10.5/centos8-amd64/gpgkeyhttps:///mirrors.aliyun.com/mariadb/yum/RPM-GPG-KEY-MariaDBmodule_hotfixes…...
Java EE 进阶:Spring IoCDI
IOC的简单介绍 什么是Spring?Spring是一个开源的框架,让我们的开发更加的简单,我们可以用一句更加具体的话来概括Spring,就是Spring是一个包含众多工具方法的IOC容器。 简单介绍一下IOC,我们之前说过通过ReqestContr…...