(1)訓練部件分割(partseg)模型和檢測自己點云并將結果保存txt,請看博主上兩篇文章
(2)本文背景是將pipe點云上的缺陷和本體檢測出來,即1種語義場景(pipe),2種類別(body和quexian)。請記住這兩個數字。
一、標注數據集:
step1:數據集預處理
參考:Windows11和Ubuntu用PointNet++訓練自己的數據集(部件分割模型)的第一部分即“一、標注數據集”
部分即可。得到分類好的n行4列
的txt文件。如果是部件分割(partseg)就結束了,但這里是語義分割(semseg)標注很麻煩,還沒完成!我這里操作完后得到了m
個txt文件,即原本有m
個pipe的點云txt文本。
step1結果:
step2:學習語義分割數據集的格式
參考:S3DIS場景點云數據集,仔細閱讀
這里用Stanford3dDataset_v1.2_Aligned_Version
模式。格式是x y z r g b格式 即n行6列
。
step3:制作語義分割txt格式數據集(可以問deepseek,見step3末尾)
思路:用matlab依次遍歷step1中每個txt點云文件,在進行操作:將標簽為0的點,去掉0并將后三位替換為某個rgb值,再將標簽為1的點后三位替換為另外某個rgb值。(因為我只有兩個類別,所以我就只有0和1。)。
注意:最后要符合語義分割數據集的格式,即每個場景(即step1得到的每個txt文件)單獨一個文件夾名字叫做pipe_i(i從1到
m
),文件夾下存著step1結果中第m個點云(n行6列)pipe_i.txt還有一個Annotations文件夾。Annotations文件夾下有2個txt文件(本文的2種類別),分別是body_i.txt和quexian_i.txt,即兩種類別的n行6列的文本文件。邏輯是:body_i.txt + quexian_i.txt=pipe_i.txt
step3結果:
deepseek實現step3
我的某個文件夾里有42個txt文件,名字分別是1.txt~42.txt.每個txt文件有n行4列,中間用空格隔開,即每個文件有n個空間點 前三列是xyz后一列是標簽,這42個文件里的每個點只有兩個標簽即0和1可能是浮點型。你也知道上面這種格式是做pointnet++部件分割的,現在我要改成語義分割,需要把標簽變成rgb。所以現在要你遍歷每個txt文件(可以用for數字遍歷,因為名字有規律),把每個文件里的0標簽的點換為rgb為[0 0 1],1標簽是換為[1 0 0]即n行6列xyzrgb 每列用空格隔開。但是要求每個txt要單獨建立一個文件夾叫做pipe_i,i是和i.txt的i相對應。pipe_i文件夾下有個pipe_i.txt放著i.txt的變換好的文件,pipe_i文件夾下的Annotations文件夾下有單獨的按照標簽的txt,之前為0標簽的點標簽變換rgb后就放到命名為body_i.txt,之前為1標簽的點標簽變換rgb后就放到命名為quexian_i.txt。即完全符合語義分割的數據格式。matlab實現
Matlab代碼如下:運行時間會很長!!其中的rgb的值都是0~1可以自己改。
%%
%設置pointnet++語義分割數據集
% 設置輸入路徑和輸出路徑
input_path = 'D:\YinParker\Desktop\管道數據集4\biaozhu'; % 輸入文件路徑
output_root = 'D:\YinParker\Desktop\管道數據集4\semseg'; % 輸出根目錄% 創建輸出根目錄(如果不存在)
if ~exist(output_root, 'dir')mkdir(output_root);
end% 遍歷1.txt到42.txt
for i = 1:42% 輸入文件名input_filename = fullfile(input_path, sprintf('%d.txt', i));% 檢查文件是否存在if ~exist(input_filename, 'file')fprintf('文件不存在: %s\n', input_filename);continue;end% 讀取數據data = load(input_filename);xyz = data(:, 1:3);labels = data(:, 4);% 創建對應的輸出目錄結構pipe_dir = fullfile(output_root, sprintf('pipe_%d', i));annotations_dir = fullfile(pipe_dir, 'Annotations');if ~exist(pipe_dir, 'dir')mkdir(pipe_dir);endif ~exist(annotations_dir, 'dir')mkdir(annotations_dir);end% 準備轉換后的數據(xyzrgb)rgb_data = zeros(size(data, 1), 6);rgb_data(:, 1:3) = xyz;% 分離不同標簽的點(帶RGB)body_points = [];quexian_points = [];for j = 1:size(data, 1)if abs(labels(j)) < 0.5 % 處理浮點型標簽% 標簽0 -> 藍色 [0 0 1]rgb_data(j, 4:6) = [0 0 1];body_points = [body_points; xyz(j, :), 0, 0, 1]; % 添加RGBelse% 標簽1 -> 紅色 [1 0 0]rgb_data(j, 4:6) = [1 0 0];quexian_points = [quexian_points; xyz(j, :), 1, 0, 0]; % 添加RGBendend% 保存轉換后的主文件(pipe_i.txt)output_main_file = fullfile(pipe_dir, sprintf('pipe_%d.txt', i));dlmwrite(output_main_file, rgb_data, 'delimiter', ' ');% 保存帶RGB的標簽文件(Annotations/body_i.txt和quexian_i.txt)if ~isempty(body_points)body_file = fullfile(annotations_dir, sprintf('body_%d.txt', i));dlmwrite(body_file, body_points, 'delimiter', ' ');endif ~isempty(quexian_points)quexian_file = fullfile(annotations_dir, sprintf('quexian_%d.txt', i));dlmwrite(quexian_file, quexian_points, 'delimiter', ' ');endfprintf('已處理文件: %s\n', input_filename);
endfprintf('所有文件處理完成!結果保存在: %s\n', output_root);
step4:txt格式數據集變為npy
語義分割需要.npy格式的數據集,這也是麻煩的地方。
在PointNet++工程文件夾下的data文件夾建立s3dis文件夾,再在s3dis里面建立Stanford3dDataset_v1.2_Aligned_Version文件夾,里面有Area_1和Area_2兩個文件夾。后面會在程序參數設置中讓Area_2里的數據為測試集
。再從step3中的pipe_i文件夾里找點文件復制進去,當做訓練集(Area1)和測試集(Area2)。結構圖如下:
再在data文件夾下建立stanford_indoor3d用于存儲npy格式的文件。
再修改anno_paths.txt和class_names.txt ,anno_paths.txt寫所有Area的Annotations的路徑,class_names.txt寫類別,和之前的step3中得到的Annotions里的相對應。
用collect_indoor3d_data.py和indoor3d_util.py將txt樣本變為npy樣本 。參考:【PointNet++】基于自建數據訓練PointNet++場景語義分割網絡
(1)collect_indoor3d_data.py修改:1/1 加一行代碼:out_filename=os.path.basename(os.path.join(output_folder, out_filename)),不然生成的npy文件路徑不對,還得自己復制到data/stanford_indoor3d文件夾下
(2)indoor3d_util.py修改: 改方框的兩處地方:
運行
collect_indoor3d_data.py
在 data/stanford_indoor3d文件夾下生成npy文件,且前面有Area_1和2的前綴。
二、修改訓練和測試代碼以及S3DISDataLoader.py
參考:
【PointNet++】基于自建數據訓練PointNet++場景語義分割網絡
【PointNet++】PointNet++復現(PyTorch版本)
1、訓練代碼修改:train_semseg.py
(1)類別:
(2)改參數:其中最后一個參數指定哪個Area是測試集,剩下參數都根據實際調整
(3)類別數:
(4)(5)numpy版本問題
2、測試代碼修改:test_semseg.py
測試的參數batch_size、num_point等參數根據自己實際調整
(1)類別:
(2)類別數量:
3、S3DISDataLoader.py
修改
參考文獻中老哥少改了一個
(1)數字:
(2)數字:得+1
(3)數字:
(4)補充: 其實后面兩個也不用改,因為后兩個在class ScannetDatasetWholeScene
而前兩個在class S3DISDataset(Dataset):
里,這里只用到了class S3DISDataset(Dataset):
pointnet2_sem_seg.py改動
用這個模型就改,不用這個就改別的模型
三、訓練以及訓練中報錯:
運行train_semseg.py即可開啟訓練。
報錯1:
Traceback (most recent call last):File "D:\YinParker\Desktop\AllFileFolder\A_Other_projects_in_laboratory\pointNet2\Pointnet_Pointnet2_pytorch-master\train_semseg.py", line 302, in <module>main(args)File "D:\YinParker\Desktop\AllFileFolder\A_Other_projects_in_laboratory\pointNet2\Pointnet_Pointnet2_pytorch-master\train_semseg.py", line 186, in mainfor i, (points, target) in tqdm(enumerate(trainDataLoader), total=len(trainDataLoader), smoothing=0.9):File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\site-packages\torch\utils\data\dataloader.py", line 438, in __iter__return self._get_iterator()File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\site-packages\torch\utils\data\dataloader.py", line 386, in _get_iteratorreturn _MultiProcessingDataLoaderIter(self)File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\site-packages\torch\utils\data\dataloader.py", line 1039, in __init__w.start()File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\multiprocessing\process.py", line 121, in startself._popen = self._Popen(self)File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\multiprocessing\context.py", line 224, in _Popenreturn _default_context.get_context().Process._Popen(process_obj)File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\multiprocessing\context.py", line 336, in _Popenreturn Popen(process_obj)File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__reduction.dump(process_obj, to_child)File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\multiprocessing\reduction.py", line 60, in dumpForkingPickler(file, protocol).dump(obj)
AttributeError: Can't pickle local object 'main.<locals>.<lambda>'
Traceback (most recent call last):File "<string>", line 1, in <module>File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\multiprocessing\spawn.py", line 116, in spawn_mainexitcode = _main(fd, parent_sentinel)File "E:\ProfessionSoftware2\anaconda\anaconda3202303\envs\yolov8Python310\lib\multiprocessing\spawn.py", line 126, in _mainself = reduction.pickle.load(from_parent)
EOFError: Ran out of input
原因:gpt說是train_semseg.py有兩處lambda表達式在window不行
法一:改lanbda表達式(推薦法二)
(1)改:參考行號
(2)得import functools
法二:
如何使用PointNet++復現自己的點云語義分割數據集?
如果你是windows系統,那你應該還要注意num_workers設置為0,否則會報錯的。 僅需改兩處
報錯2:
也不是報錯,就是訓練代碼運行后一直卡住,
原因:S3DISDataLoader.py
里有個一直循環,點數沒有達到1024個
因為1*1平方米內自己點太少了,達不到訓練時設置的參數--npoint
(超參數)
解決方法:train_semseg.py里把參數1調大也行 或者 將上圖S3DISDataLoader.py里把1024調小
如果對你有幫助,可以點贊、收藏支持一波