PointGroup点云实例分割
⽂章⽬录
简介
分类(Classify)和分割(Segment)是视觉中两个典型的任务, ⽽分割⼜可以细分为语义分割(Semantic Segmentation)和实例分割
N N
(Instance Segmantation). 区别在于, 语义分割将输⼊中的⽬标分成个类别, 输出也是个类别. ⽽实例分割的每个输出只包含⼀个⽬标.本篇选取了PointGroup模型, 在点云上做实例分割.
环境
系统: Ubuntu16.04
Python版本: python3.7
Pytorch版本: 1.1
数据集: scannetv2
CUDA: 10.1
GPU: RTX 2080TI * 8
曹先生其中, torch版本必须为1.1, 否则会由于⼀些api变动的问题出错.
项⽬⽂件
最后的-recursive必不可少, 这个项⽬需要⽤到⼏个第三⽅的git, 该参数可以⾃动帮我们下载.
项⽬⽬录结构如下:
PointGroup/
├─config/
├─data/
├─datat/
├─doc/
├─lib/
├─model/
├─util/
环境准备
建议新建anaconda虚拟环境, 如下:
conda create -n pointgroup python==3.7
source activate pointgroup
pip install -
下⾯⼏个包, 由于⽹络问题可能会安装失败, 建议挂VPN多试⼏次. 我试了好⼏天才成功的
必须⽤这三个命令安装, 其它通过cmake安装的是没⽤的. 本来由于google-sparhash装不上, 我⼀开始装了c++版本的, 结果发现没⽤conda install -c bioconda google-sparhash
conda install libboost
conda install -c daleydeng gcc-5
spconv
接着, 找到系统中boost/的路径, 修改lib/中的include_directories($INCLUDE_PATH$)这⼀句
此时就可以编译spconv了:
cd lib/spconv
python tup.py bdist_wheel
江西奉新
cd dist
pip install${whl}
其中, ${whl}是编译成功后⽣成的whl⽂件, 可以直接通过pip安装.
pointgroup_ops
编译过程如下:
cd lib/pointgroup_ops
python tup.py develop
如果有提⽰某个头⽂件找不到, 在新建的anaconda PointGroup虚拟环境下, 找到这个头⽂件(只要前⾯所有的conda install成功, 这些头⽂件肯定是在这个虚拟环境下的,花点时间找⼀下即可), ⽤下⾯的命令把头⽂件加进去, 缺啥加啥:
python tup.py build_ext --include-dirs=${INCLUDE_PATH}
python tup.py develop
其中${INCLUDE_PATH}就是缺失的头⽂件的路径
数据集
稿子下载脚本
论⽂采⽤的是Scannetv2数据集, 由于版权问题, 请各位前往, 按照README.md⾥⾯的步骤, 复制Scan
Net Terms of U.pdf⾥⾯的内容到word, 填好之后再转到ScanNet Terms of U.pdf中, 已附件的形式发送给, ⼀周内作者会给你发送⼀个下载数据集的download-scannet.py脚本和运⾏教程
拿到这个download-scannet.py脚本后, 如果是在Python2环境下, 可以直接运⾏, 如果是Python3环境, 需要将其中有关urllib的代码做⼀些改动, 改动⽅法很简单, 将所有的urllib改为quest即可
下载数据集
整个scannetv2数据集⼤⼩为1.3TB, 这么⼤的⼤⼩显然不可能全部下载. 所幸模型需要的数据只有20GB. ⼀共有下⾯四类后缀名的⽂件需要下载:
_vh_clean_2.ply
_vh_clean_2.labels.ply
_vh_clean_2.0.010000.gs.json
.aggregation.json
因此需要运⾏下⾯四个命令:
python3 download-scannet.py -o scannet/ --type _vh_clean_2.ply
python3 download-scannet.py -o scannet/ --type _vh_clean_2.labels.ply
python3 download-scannet.py -o scannet/ --type _vh_clean_2.0.010000.gs.json
python3 download-scannet.py -o scannet/ --type .aggregation.json
这四个下载任务, 在下载完所有指定后缀名的⽂件后, 还会下载4个同样的.zip⽂件, 但是不知道什么原因, 这些.zip⽂件没办法通过脚本下载(会报错). 但是这些.zip⽂件根本在这个项⽬张洪没有⽤到, 因此如果各位在下载完的时候发现, 终端有报错说某个.zip⽂件下载失败, 这是不影响的.
下载完成后, 数据集的⽬录结构是这样的(只给出⽬录结构, 不给出所有⽂件):
├── scannet
│├── scans
││├──[scene_id]# 每个⽂件夹下应该有下⾯4个⽂件
│││├──[scene_id].aggregation.json
│││├──[scene_id]_vh_clean_2.0.010000.gs.json
│││├──[scene_id]_vh_clean_2.labels.ply
│││├──[scene_id]_vh_clean_2.ply
│├── scans_test
││├──[scene_id]# 每个⽂件夹下应该有下⾯1个⽂件
│││├──[scene_id]_vh_clean_2.ply
│├──
业绩长虹的意思│├──
│├──
│├── bined.tsv
划分数据集
这⾥我写了⼀个脚本scannet_split.py来验证数据集的完整性. 如下:
import os
dir_scans ='scannet/scans/'
dir_scans_test ='scannet/scans_test/'
dir_train ='datat/scannetv2/train/'
dir_val ='datat/scannetv2/val/'
dir_test ='datat/scannetv2/test/'
for dir_ in[dir_test, dir_val, dir_train]:
if not ists(dir_):
os.makedirs(dir_)
def read_from_txt(path_txt):
file=open(path_txt,'r')过新年儿童画
data =[]
for line in file:
data.append(line.split('\n')[0])
return data
def check_files():
"""
先运⾏这个函数, 确保所有需要的⽂件都已经下载到了指定路径
"""
print('[INFO] begin checking files')
for scan_name in os.listdir(dir_scans):
print('[INFO] checking scan {} ...'.format(dir_scans + scan_name))
check1 = ists(dir_scans + scan_name +'/{}_vh_clean_2.ply'.format(scan_name))
check2 = ists(dir_scans + scan_name +'/{}_vh_clean_2.labels.ply'.format(scan_name))
check3 = ists(dir_scans + scan_name +'/{}_vh_clean_2.0.010000.gs.json'.format(scan_name))
check4 = ists(dir_scans + scan_name +'/{}.aggregation.json'.format(scan_name))
asrt check1,'[ERROR] scan {} has no `_vh_clean_2.ply` file'.format(dir_scans + scan_name)
asrt check2,'[ERROR] scan {} has no `_vh_clean_2.labels.ply` file'.format(dir_scans + scan_name)
asrt check3,'[ERROR] scan {} has no `_vh_clean_2.0.010000.gs.json` file'.format(dir_scans + scan_name) asrt check4,'[ERROR] scan {} has no `.aggregation.json` file'.format(dir_scans + scan_name)
print('[INFO] checking done')银耳木瓜汤
for scan_name in os.listdir(dir_scans_test):
print('[INFO] checking scan {} ...'.format(dir_scans_test + scan_name))
check1 = ists(dir_scans_test + scan_name +'/{}_vh_clean_2.ply'.format(scan_name))
asrt check1,'[ERROR] scan {} has no `_vh_clean_2.ply` file'.format(dir_scans + scan_name)
print('[INFO] checking done')
print('[INFO] checking done')
print('[INFO] checking files complete, all files exist')
def copy_files_to_dir(dir_to, path_files):
for file in path_files:
cmd ='cp {} {}'.format(file, dir_to)
关于月的诗句
os.system(cmd)
print('[INFO] ', cmd)
def split_train_test_val():
"""
再运⾏这个函数, 将下载好的数据集, 按train, val, test划分, 然后复制到指定路径
"""
print('[INFO] begin split train, val, test')
for scan_name in os.listdir(dir_scans):
path_files =[]
if scan_name in train:
print('[INFO] scan {} '.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}_vh_clean_2.ply'.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}_vh_clean_2.labels.ply'.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}_vh_clean_2.0.010000.gs.json'.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}.aggregation.json'.format(scan_name))
copy_files_to_dir(dir_train, path_files)
银河渡口打一地名elif scan_name in val:
print('[INFO] scan {} '.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}_vh_clean_2.ply'.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}_vh_clean_2.labels.ply'.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}_vh_clean_2.0.010000.gs.json'.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}.aggregation.json'.format(scan_name))
copy_files_to_dir(dir_val, path_files)
for scan_name in os.listdir(dir_scans_test):
print('[INFO] scan {} '.format(scan_name))
path_files.append(dir_scans + scan_name +'/{}_vh_clean_2.ply'.format(scan_name))
copy_files_to_dir(dir_test, path_files)
if __name__ =='__main__':
check_files()
print('='*50,'\n')
train = read_from_txt('scannet/')
val = read_from_txt('scannet/')
test = read_from_txt('scannet/')
split_train_test_val()
该脚本可以直接运⾏, 只要运⾏期间没有报错, 说明数据集已经按要求准备好了.
准备好后, PointGroup/datat的⽬录结构是这样的:
PointGroup
├── datat
│├── scannetv2
││├── train
│││├──[scene_id]_vh_clean_2.ply &[scene_id]_vh_clean_2.labels.ply &[scene_id]_vh_clean_2.0.010000.gs.json &[scene_id].aggregation.json ││├── val
│││├──[scene_id]_vh_clean_2.ply &[scene_id]_vh_clean_2.labels.ply &[scene_id]_vh_clean_2.0.010000.gs.json &[scene_id].aggregation.json ││├──test
│││├──[scene_id]_vh_clean_2.ply
││├── bined.tsv
最后, ⽤以下命令⽣成训练需要的⽂件即可:
cd datat/scannetv2
python prepare_data_inst.py --data_split train
python prepare_data_inst.py --data_split val
python prepare_data_inst.py --data_split test
训练
CUDA_VISIBLE_DEVICES=0 python train.py --config config/pointgroup_run1_scannet.yaml
具体的参数都在config/pointgroup_run1_scannet.yaml⽂件中, 可以⾃由更改. 训练完成后会在PointGroup/exp/⽬录下保存权重和⽇志. 可以
⽤tensorboardX打开:
tensorboard --logdir=./exp --port=6666
测试&可视化
作者给出了预训练完的权重, . 可以直接⽤这个权重做测试:
CUDA_VISIBLE_DEVICES=0 python test.py --config config/pointgroup_default_scannet.yaml --pretrain $PATH_TO_PRETRAIN_MODEL$
如果需要保存每个点的offt和instance_g, 需要改动config/pointgroup_default_scannet.yaml中, 最后的⼏⾏:
TEST:
split: val
test_epoch:384
test_workers:16
test_ed:567
TEST_NMS_THRESH:0.3
TEST_SCORE_THRESH:0.09
TEST_NPOINT_THRESH:100
eval:True
save_mantic:True
save_pt_offts:True
save_instance:True
可视化
README.md中的可视化⽅法过于复杂, mayavi在安装和使⽤的时候各种出错.因此我打算⽤⾃⼰的⽅法做可视化(如果能按他的⽅法顺利执⾏那就没问题, 可能我这种情况是个例).
然⽽现在碰到问题是, 他测试结果中的所有mask⽂件全是0. 置信度和分类信息是清楚的, 但是缺少了实例分割后的点云⽂件.
因此这⾥可视化先挖个坑…等解决了再填吧…点云模型不能可视化是个⼤问题