@@ -818,5 +818,89 @@ class PointNetFeaturePropagation(nn.Module):
818
818
819
819
- new_points: 每个原始点都有了一个新的特征向量 [ B, D', N]
820
820
821
+ #### 点云语义分割模型
821
822
823
+ 下面给出的是一个** 基于 PointNet++** 的点云语义分割模型定义 ,其主要功能是:
822
824
825
+ - 对输入点云中的每个点进行分类(如桌子、椅子、地板等),输出每个点的类别概率。
826
+
827
+ 网络结构特点:
828
+
829
+ - 使用 Set Abstraction(SA)层 进行多尺度特征提取和下采样;
830
+
831
+ - 使用 Feature Propagation(FP)层 进行特征插值和上采样;
832
+
833
+ - 最后通过两个卷积层输出每个点的分类结果;
834
+
835
+ - 输出为 [ B, N, num_classes] ,即每个点都有一个类别预测。
836
+
837
+ ``` python
838
+ class get_model (nn .Module ):
839
+ def __init__ (self , num_classes ):
840
+ """
841
+ 初始化 PointNet++ 分割网络
842
+
843
+ 参数:
844
+ num_classes: 分类类别数
845
+ """
846
+ super (get_model, self ).__init__ ()
847
+
848
+ # Set Abstraction 层(编码器部分)
849
+ # 每层逐步下采样,并提取更高级别的局部特征
850
+ self .sa1 = PointNetSetAbstraction(npoint = 1024 , radius = 0.1 , nsample = 32 , in_channel = 9 + 3 , mlp = [32 , 32 , 64 ], group_all = False )
851
+ self .sa2 = PointNetSetAbstraction(npoint = 256 , radius = 0.2 , nsample = 32 , in_channel = 64 + 3 , mlp = [64 , 64 , 128 ], group_all = False )
852
+ self .sa3 = PointNetSetAbstraction(npoint = 64 , radius = 0.4 , nsample = 32 , in_channel = 128 + 3 , mlp = [128 , 128 , 256 ], group_all = False )
853
+ self .sa4 = PointNetSetAbstraction(npoint = 16 , radius = 0.8 , nsample = 32 , in_channel = 256 + 3 , mlp = [256 , 256 , 512 ], group_all = False )
854
+
855
+ # Feature Propagation 层(解码器部分)
856
+ # 从稀疏点恢复到原始点密度,逐层融合上下文信息
857
+ self .fp4 = PointNetFeaturePropagation(in_channel = 768 , mlp = [256 , 256 ])
858
+ self .fp3 = PointNetFeaturePropagation(in_channel = 384 , mlp = [256 , 256 ])
859
+ self .fp2 = PointNetFeaturePropagation(in_channel = 320 , mlp = [256 , 128 ])
860
+ self .fp1 = PointNetFeaturePropagation(in_channel = 128 , mlp = [128 , 128 , 128 ])
861
+
862
+ # 最终分类头
863
+ self .conv1 = nn.Conv1d(128 , 128 , 1 )
864
+ self .bn1 = nn.BatchNorm1d(128 )
865
+ self .drop1 = nn.Dropout(0.5 )
866
+ self .conv2 = nn.Conv1d(128 , num_classes, 1 )
867
+
868
+ def forward (self , xyz ):
869
+ """
870
+ 前向传播函数
871
+
872
+ 输入:
873
+ xyz: 点云数据,形状 [B, C, N]
874
+
875
+ 返回:
876
+ x: 每个点的分类结果,形状 [B, N, num_classes]
877
+ l4_points: 最后一层抽象特征,用于其他任务
878
+ """
879
+ # l0 表示最原始的点云
880
+ l0_points = xyz
881
+ l0_xyz = xyz[:, :3 , :] # 只取 xyz 坐标,不带法向量或其他属性
882
+
883
+ # 编码器:层层下采样并提取特征
884
+ l1_xyz, l1_points = self .sa1(l0_xyz, l0_points) # 1024 points
885
+ l2_xyz, l2_points = self .sa2(l1_xyz, l1_points) # 256 points
886
+ l3_xyz, l3_points = self .sa3(l2_xyz, l2_points) # 64 points
887
+ l4_xyz, l4_points = self .sa4(l3_xyz, l3_points) # 16 points
888
+
889
+ # 解码器:层层插值并融合特征
890
+ l3_points = self .fp4(l3_xyz, l4_xyz, l3_points, l4_points) # 64 → 64
891
+ l2_points = self .fp3(l2_xyz, l3_xyz, l2_points, l3_points) # 256 → 256
892
+ l1_points = self .fp2(l1_xyz, l2_xyz, l1_points, l2_points) # 1024 → 1024
893
+ l0_points = self .fp1(l0_xyz, l1_xyz, None , l1_points) # 4096 → 4096
894
+
895
+ # MLP 头部处理:进一步增强特征
896
+ x = self .drop1(F.relu(self .bn1(self .conv1(l0_points)), inplace = True )) # [B, 128, N]
897
+ x = self .conv2(x) # [B, num_classes, N]
898
+
899
+ # Softmax 分类
900
+ x = F.log_softmax(x, dim = 1 ) # [B, num_classes, N]
901
+
902
+ # 调整维度,返回 [B, N, num_classes]
903
+ x = x.permute(0 , 2 , 1 )
904
+
905
+ return x, l4_points # 返回每个点的分类结果和抽象特征
906
+ ```
0 commit comments