VPCC(video based point cloud compression)是MPEG 3DG工作组所开发的针对动态点云的压缩测试算法,核心思想是将3D点云数据通过高效的分割分方向投影算法投影到2D平面,再使用成熟的2D image压缩工具HEVC进行压缩编码。相比较于传统的octree等点云压缩算法,在率失真上展现出来更好的压缩性能。
目前算法已经更新到VPCCv8.0版本,还在持续更新中。
本教程以VPCCv7.0版本代码为例,来说明如何进行VPCC代码的测试与使用。
由于在准备的过程中需要较多的下载源码,所以建议可以使用Tortoise工具来进行源码下载,也比较方便打patch。
VPCC所使用的官方测试集包括7个测试序列,均为人物类型的密集点云测试序列,以ply形式储存。VPCC代码的输入为ply文件,输出为ply文件。
包含4个测试序列:loot,queen,longdress,redandblack
官方下载地址:
8i原始点云数据集
8i-RGB-normal点云数据集
包含一个测试序列:queen
官方下载地址:
queen原始点云数据集
queen-RGB-normal数据集
除此之外,最近MPEG会议还提供了两个新的测试序列:basketball_player和dancer,下载方法:
登录网站mpeg-cotent
进入目录下载对应的后缀为vox11的压缩包:
/MPEG-I/Part05-PointCloudCompression/dataSets/Owlii/VoxelizedPointCloud
数据集放置路径可以根据个人爱好选择放置,但是需要和后面进行测试时设置的数据集放置路径保持一致。
为了方便测试,我把所有的数据集放置在于源码包同一级目录下的ply文件夹里:
VPCC的源码下载地址:VPCC
可以在tag页面下载其他版本的VPCC:各版本VPCC
下载好源码包,之后解压缩,进入文件夹后,依次执行:
mkdir build
cd build
cmake …
make
如果不是linux操作系统下,可以参考源码包内的readme文件,里面有对应的说明。
VPCC需要使用到的依赖库主要有两个,一个是颜色空间转换工具HDRConvert,另一个是压缩所需要用到的HEVC压缩工具。(VPCC本身并没有进行编码,编码是用HEVC进行的)。
所有的依赖库的放置位置也是根据个人需求来进行即可,但是需要和后面测试时的设置保持一致。
HDRConvert v0.18
如果需要下载其他版本,可以在tags目录下寻找自己需要的版本。
解压缩之后,找到源码包中包含makefile文件的目录。
执行:
make
即可以生成bin文件夹,并生成可执行文件HDRConvert。
VPCC需要使用的HEVC压缩工具版本为HM16.20+SCM8.8,如下是源码下载地址:
HM-16.20+SCM8.8
如果需要下载其他版本,可以在tags目录下寻找自己需要的版本。
需要注意的是,由于VPCC需要HEVC支持一些拓展功能,因此在编译生成可执行文件之前,需要对HEVC源码进行一定的修改。
接下来介绍如何修改,打开我们之前下载的VPCC源码包,以VPCC V7.0为例,在mpeg-pcc-tmc2-release-v7.0/dependencies/hm-modification/目录下,有两个patch文件:
需要将pcc开头的patch文件应用到下载好的HM源码包中。之所以在开篇的时候建议使用Tortoise来下载源码,有一个原因就是使用Tortoise下载的源码包,可以比较方便的apply patch。
在完成对于HM源码包的修改之后,在HM源码包的build/linux/目录下,执行:
make
即可以发现在bin文件目录下生成了对应的可执行文件:
TAppEncoderStatic和TAppDecoderStatic。
数据集放置路径可以根据个人爱好选择放置,但是需要和后面进行测试时设置的数据集放置路径保持一致。
为了方便测试,我把所有的数据集放置在于源码包同一级目录下的external文件夹里:
至此,所有的准备工作已经完成,可以开始测试VPCC算法了。
打开VPCC源码包的test文件夹,里面有官方提供的测试模板文件,runme_linux.sh。可以通过执行:
sh runme_linux.sh
来进行测试,但是运行之前,需要确保sh脚本文件中的参数与你的配置路径保持一致。我对其进行了一定的修改,为了方便进行并行测试,在test文件夹里新建了seq22-28的文件夹,每个文件夹下分别新建了r1-r5的文件夹,来将各种测试序列压缩率的测试结果分别储存,以此为例:
#!/bin/bash
MAINDIR=$( dirname $( cd "$( dirname $0 )" && pwd ) );
EXTERNAL=$( dirname $MAINDIR )/external_pkg
if [ ! -d $EXTERNAL ] ; then EXTERNAL=$( dirname $MAINDIR )/external; fi
## Input parameters
SRCDIR=$( dirname $MAINDIR )/ply/ # note: this directory must containt: http://mpegfs.int-evry.fr/MPEG/PCC/DataSets/pointCloud/CfP/datasets/Dynamic_Objects/People
CFGDIR=${MAINDIR}/cfg/
TESTDIR=${MAINDIR}/test/
for RATE in 1 2 3 4 5;
do
SEQ=23; # in [22;26]
COND=C2RA; # in [C2AI, C2RA, CWAI, CWRA]
FRAMECOUNT=32;
THREAD=1;
##Set external tool paths
ENCODER="set_value";
DECODER="set_value";
HDRCONVERT="set_value";
HMENCODER="set_value";
HMDECODER="set_value";
HMAXENCODER="set_value";
if [ ! -f $ENCODER ] ; then ENCODER=${MAINDIR}/bin/PccAppEncoder; fi
if [ ! -f $DECODER ] ; then DECODER=${MAINDIR}/bin/PccAppDecoder; fi
if [ ! -f $HDRCONVERT ] ; then HDRCONVERT=${EXTERNAL}/HDRTools/bin/HDRConvert; fi
if [ ! -f $HMENCODER ] ; then HMENCODER=${EXTERNAL}/HM-16.20+SCM-8.8+patch/bin/TAppEncoderStatic; fi
if [ ! -f $HMDECODER ] ; then HMDECODER=${EXTERNAL}/HM-16.20+SCM-8.8+patch/bin/TAppDecoderStatic; fi
if [ ! -f $HMAXENCODER ] ; then HMAXENCODER=${EXTERNAL}/HM-16.20+SCM-8.8+patch/bin/TAppEncoderStatic; fi
## Parameters and pathes check
if [ ! -f $ENCODER ] ; then echo "Can't find PccAppEncoder, please set. ($ENCODER )"; exit -1; fi
if [ ! -f $DECODER ] ; then echo "Can't find PccAppDecoder, please set. ($DECODER )"; exit -1; fi
if [ ! -f $HDRCONVERT ] ; then echo "Can't find HdrConvert, please set. ($HDRCONVERT)"; exit -1; fi
if [ ! -f $HMENCODER ] ; then echo "Can't find TAppEncoderStatic, please set. ($HMENCODER)"; exit -1; fi
if [ ! -f $HMDECODER ] ; then echo "Can't find TAppDecoderStatic, please set. ($HMDECODER)"; exit -1; fi
if [ ! -f $HMAXENCODER ] ; then echo "Can't find TAppAuxEncoderStatic, please set. ($HMAXENCODER)"; exit -1; fi
## Set Configuration based on sequence, condition and rate
case $SEQ in
22) CFGSEQUENCE="sequence/queen.cfg";;
23) CFGSEQUENCE="sequence/loot_vox10.cfg";;
24) CFGSEQUENCE="sequence/redandblack_vox10.cfg";;
25) CFGSEQUENCE="sequence/soldier_vox10.cfg";;
26) CFGSEQUENCE="sequence/longdress_vox10.cfg";;
*) echo "sequence not correct ($SEQ)"; exit -1;;
esac
case $SEQ in
22) STARTNUM=0;;
23) STARTNUM=1000;;
24) STARTNUM=1450;;
25) STARTNUM=536;;
26) STARTNUM=1051;;
*) echo "sequence not correct ($SEQ)"; exit -1;;
esac
case $RATE in
5) RATEF="r5/";;
4) RATEF="r4/";;
3) RATEF="r3/";;
2) RATEF="r2/";;
1) RATEF="r1/";;
*) echo "rate not correct ($RATE)"; exit -1;;
esac
case $SEQ in
22) RESULTS="seq22/";;
23) RESULTS="seq23/";;
24) RESULTS="seq24/";;
25) RESULTS="seq25/";;
26) RESULTS="seq26/";;
*) echo "sequence not correct ($SEQ)"; exit -1;;
esac
case $RATE in
5) CFGRATE="rate/ctc-r5.cfg";;
4) CFGRATE="rate/ctc-r4.cfg";;
3) CFGRATE="rate/ctc-r3.cfg";;
2) CFGRATE="rate/ctc-r2.cfg";;
1) CFGRATE="rate/ctc-r1.cfg";;
*) echo "rate not correct ($RATE)"; exit -1;;
esac
case $SEQ in
22) NSEQUENCE="Technicolor/queen_n/frame_%04d_n.ply";;
23) NSEQUENCE="8i/8iVFBv2/loot/loot_n/loot_vox10_%04d_n.ply";;
24) NSEQUENCE="8i/8iVFBv2/redandblack/redandblack_n/redandblack_vox10_%04d_n.ply";;
25) NSEQUENCE="8i/8iVFBv2/soldier/soldier_n/soldier_vox10_%04d_n.ply";;
26) NSEQUENCE="8i/8iVFBv2/longdress/longdress_n/longdress_vox10_%04d_n.ply";;
*) echo "sequence not correct ($SEQ)"; exit -1;;
esac
case $SEQ in
22) UNSEQUENCE="Technicolor/queen/frame_%04d.ply";;
23) UNSEQUENCE="8i/8iVFBv2/loot/Ply/loot_vox10_%04d.ply";;
24) UNSEQUENCE="8i/8iVFBv2/redandblack/Ply/redandblack_vox10_%04d.ply";;
25) UNSEQUENCE="8i/8iVFBv2/soldier/Ply/soldier_vox10_%04d.ply";;
26) UNSEQUENCE="8i/8iVFBv2/longdress/Ply/longdress_vox10_%04d.ply";;
esac
BIN=S${SEQ}${COND}R0${RATE}_F${FRAMECOUNT}.bin
case $COND in
CWAI) CFGCOMMON="common/ctc-common-lossless-geometry-texture.cfg";;
CWLD) CFGCOMMON="common/ctc-common-lossless-geometry-texture.cfg";;
C2AI) CFGCOMMON="common/ctc-common.cfg";;
C2RA) CFGCOMMON="common/ctc-common.cfg";;
*) echo "Condition not correct ($COND)"; exit -1;;
esac
case $COND in
CWAI) CFGCONDITION="condition/ctc-all-intra-lossless-geometry-texture.cfg";;
CWLD) CFGCONDITION="condition/ctc-low-delay-lossless-geometry-texture.cfg";;
C2AI) CFGCONDITION="condition/ctc-all-intra.cfg";;
C2RA) CFGCONDITION="condition/ctc-low-delay.cfg";;
*) echo "Condition not correct ($COND)"; exit -1;;
esac
MetricResolution=1023
if [ $SEQ == 27 -o $SEQ == 28 ]
then MetricResolution=2047
fi
## Encoder
if [ ! -f $BIN ]
then
$ENCODER \
--config=${CFGDIR}${CFGCOMMON} \
--config=${CFGDIR}${CFGSEQUENCE} \
--config=${CFGDIR}${CFGCONDITION} \
--config=${CFGDIR}${CFGRATE} \
--configurationFolder=${CFGDIR} \
--uncompressedDataFolder=${SRCDIR} \
--normalDataPath=${SRCDIR}${NSEQUENCE} \
--frameCount=$FRAMECOUNT \
--colorSpaceConversionPath=$HDRCONVERT \
--videoEncoderPath=$HMAXENCODER \
--videoEncoderOccupancyMapPath=$HMENCODER\
--nbThread=$THREAD \
--keepIntermediateFiles=1 \
--resolution=$MetricResolution \
--reconstructedDataPath=${TESTDIR}${RESULTS}${RATEF}${BIN%.???}_rec_%04d.ply\
--compressedStreamPath=${TESTDIR}${RESULTS}${RATEF}$BIN
fi
## Decoder
$DECODER \
--compressedStreamPath=${TESTDIR}${RESULTS}${RATEF}$BIN \
--uncompressedDataPath=${SRCDIR}${UNSEQUENCE} \
--normalDataPath=${SRCDIR}${NSEQUENCE} \
--videoDecoderPath=${HMDECODER} \
--colorSpaceConversionPath=${HDRCONVERT} \
--inverseColorSpaceConversionConfig=${CFGDIR}/hdrconvert/yuv420torgb444.cfg \
--nbThread=$THREAD \
--startFrameNumber=$STARTNUM\
--resolution=$MetricResolution\
--reconstructedDataPath=${TESTDIR}${RESULTS}${RATEF}${BIN%.???}_dec_%04d.ply\
done
该sh脚本实现的是,对于seq23的rate1到5的测试。
几个重要的脚本参数:
(1)COND:脚本中的测试条件为C2RA测试条件,如果要修改测试条件,请修改COND参数,以及对应的CFGSEQUENCE参数。如果要进行无损压缩(CWAI或者CWLD),CFGSEQUENCE需要修改为包含lossless的cfg文件。
(2)FRAMECOUNT:需要压缩的帧数。
(3)RATE:压缩的码率,RATE越高,压缩率越低,但是对应的质量越高。
只要注意修改参数,就可以随意的进行自己需要的测试了。
因为可能不是所有人都有linux系统,所以可能需要使用ssh连接远程服务器来运行。但是由于VPCC运行时间较长,所以可能由于网络中断,导致运行不成功。
在此提供一下远程测试防止程序中断的解决方法。主要参考:
SSH连接linux服务器防中断
参考博客提供了三种解决办法,个人推荐使用screen的方法。
可以简单的使用
screen -L sh runme_linux.sh
来执行程序,这样可以在test文件夹下面生成一个log文件,来记录屏幕输出。
如果网络中断,或者退出ssh连接,程序依旧会执行下去,直到运行结束或者报错。
这样的话就可以把ssh关掉,自己去做自己的事情,需要来检查的时候,再次连接服务器,输入:
screen -ls
screen -r 27267
就可以重新进入之前打开的进程了。
如果要终止进程:
kill 27267
不过这样运行的话,如果同时进行多个任务,就有可能把所有的屏幕日志输出到同一个log文件,导致记录混乱。为了解决这一问题,可以参考:
linux screen技巧
修改配置文件,来使每一次screen窗口保存的log文件不同就可以了。