pyton3.x上的SMPLify运行

SMPLify Demo Test

为了验证之前提出的毕设方案的可行性,这个星期的主要任务是配置环境运行 SMPLify 的 demo 代码,但这个过程中还是遇到不少问题的。

首先,SMPLify 的依赖库有 numpy、scipy、chumpy、opendr、matplotlib、opencv、openGL、SMPL 等,其中:chumpy、opendr、SMPL 仅支持 Python 2.x 版本。但是,考虑到我们之后可能会用到基于 Python 3.x 的外部库(如 Tensorflow 等),我们要先修改这些依赖库的代码,使它们兼容 Python 3.x。

我们先使用 pip3 install 来安装这些依赖库,但在这个过程中,我发现无法通过 pip3 来安装 opendr 与 SMPL。当我们尝试用 pip3 安装 SMPL 时,会出现 No matching distribution found for SMPL 的报错,而原因也很简单,因为 SMPL 并不是很流行的库,所以很有可能只能手动进行安装。而无法通过 pip3 安装 opendr 是因为 opendr 只支持 Python 2.x,通过 pip3 下载的 opendr 的 whl 会无法正常运行 setup.py。最后,我在 google 上搜寻了很多资料,终于在这个网站上找到了兼容 python3.5 版本的 opendr。我们运行 opendr 文件夹中的 setup.py 文件,依次执行以下两条指令完成安装:python3.5 setup.py build、python3.5 setup.py install。然后,我从 SMPL 的官方网站上下载了 SMPL for Python version 1.0.0 的代码。我们要手动安装的话要先进入 Python 的 site-package 路径,然后新建一个 pth 文件,里面保存 SMPL 的安装目录,将 SMPL 的目录添加到 Python 的检测路径中。

到这一步,我们先尝试运行 SMPL 提供的 demo 代码 – hello_smpl.py。此时,版本不兼容的问题就体现出来了。我遇到的第一个问题是 ImportError: No module named xxxx,它出现的原因是 Python2.x 与 Python3.x 的 import 操作有些许差别。假设在 a 文件夹下有文件 b.py 与 c.py,在 Python2.x 中我们可以在 b.py 中使用 import c 来引用 c.py;在 Python3.x 中,我们要改用 import a.c。这个问题出现在了 chumpy、opendr、SMPL 中的一些列代码文件中,这里就不一一列举了。

遇到的第二个问题是若干系统库的修改,如:在 Python3.x 中 CPickle 与 pickle 被整合成了 pickle;Xrange 与 range 被整合成了 range;NameError: name ‘reduce’ is not defined,reduce 不再存在于 build-in function 中,使用前要先 from functools import reduce;object of type ‘generator’ has no len(),Python3.x 的返回类型与 Python2.x 不一样,要把 generator 先转换为 list;’function’ object has no attribute ‘func_name’,func_name 被更改为 __name__;unsupported operand type(s) for +: ‘range’ and ‘list’,要先把 range 转换为 list。

最后遇到的最麻烦的问题是 SMPL 库的某些操作会引起 unsupported operand type(s) 报错,在排查了一轮之后我发现 Python3.x 的对 __div__ 与 __mul__ 的重载有些不一样了,我们要手动修改部分代码中的运算符。且外,pickle 的读写格式也不再默认支持二进制,我们需要把 mode 设为 rb 或 wb。其实整个过程中还有其他很多问题,但是我没能一一记住,这里就不赘述了。

努力了一番过后,我终于成功运行了 SMPL 的 hello_smpl.py 文件,这里的关节点是 SMPL 给出的测试数据,运行 hello_smpl.py 可以将对应的 pkl 文件转换为 obj 模型。

pyton3.x上的SMPLify运行_第1张图片

然而,我们的工作还没结束,我们还需要跑通 SMPLify 的 demo 代码 – fit_3d.py。我们先从官网上下载 SMPLify Code and model。我们用前文提到过的方法配置好路径后,还需要在网上下载 lsp 运动姿势照片 dataset,但是这个 dataset 貌似已经被官网下架了,努力了一番后还是在 github 上找到了照片集。且外,我们也要用到从 DeepCut 提取的 lsp dataset 的二维特征点,但由于时间问题,我没有时间去尝试运行 DeepCut,暂时先使用了现有的已经提取好的特征点。关于 DeepCut 的内容,我会在尽快尝试运行。对 SMPLify 源码进行一系列的修改后,我们终于可以运行 fit_3d.py 了。对于一幅给定的 lsp 图片,fit_3d.py 会生成对应的模型截图与 pkl 文件。


pyton3.x上的SMPLify运行_第2张图片
pyton3.x上的SMPLify运行_第3张图片

但是,在我尝试使用刚刚得到的 pkl 文件来生成对应的 obj 文件或者其他格式的 mesh 时,我却发现 pkl 无法正常读取。由于目前还有两个课程项目还没来得及完成,一时半刻间我也没办法解决这个问题,所以在这次的周报中暂时保留这个问题,我会争取在这周完成 DeepCut 的测试与读取 pkl 的测试,并尽量使用自己定义的图片来测试 SMPLify 的效果。


SMPLify Demo Test 2

在上次运行 demo 的基础上,我们这次将尝试运行自己的测试样例,而不是 SMPLify 提供的 LSP dataset。

上次测试的时候,我们还留有一个问题尚未解决:在 SMPLify 上对 LSP dataset 进行测试后无法获得对应的 pkl 文件。在仔细研究了源代码后,我发现这个问题是 Python2 与 Python3 在读写文件上有差别所导致的。为了解决这个问题,我们需要先定位到 ‘fit_3d.py’ 中的:

with open(out_path, 'wb+') as outf:
    pickle.dump(params, outf)


我们把这两行代码改成如下形式,即可获得保存关节点数据的 pkl 文件了:

with open(out_path, 'w+') as tmp:
    tmp.write(params.__str__())

接下来,我们要尝试使用 SMPLify 测试我们自己的输入图片。

首先,我们需要获取输入图片的 DeepCut 预测关节点,经由 DeepCut 获得的 14 个关节点与 SMPLify 关节点的对应关系如下:

index joint name corresponding SMPL joint ids
0 Right ankle 8
1 Right knee 5
2 Right hip 2
3 Left hip 1
4 Left knee 4
5 Left ankle 7
6 Right wrist 21
7 Right elbow 19
8 Right shoulder 17
9 Left shoulder 16
10 Left elbow 18
11 Left wrist 20
12 Neck -
13 Head top vertex 411 (see line 233:fit_3d.py)


而 DeepCut 关节点的输出格式如下:

The pose in 5x14 layout. The first axis is along per-joint information,
the second the joints. Information is:
  1. position x,
  2. position y,
  3. CNN confidence,
  4. CNN offset vector x,
  5. CNN offset vector y.


在此,我们需要用到的 DeepCut 关节点数据为其输出的前三维,即:x 坐标、y 坐标、预测 confidence。

在尝试安装 DeepCut 的依赖库 Caffe 时,我遇到了不少的问题,最终耗费了不少时间才成功运行 DeepCut。因此,我先简单描述一下 DeepCut 的环境配置操作。

最开始的时候,我分别尝试了在 macOS 与 Ubuntu 16.04 上安装 Caffe,具体教程可以参照以下网址。但是,Caffe 框架使用到了很多依赖库,我们简单地通过 pip3 安装这些依赖库的话,会出现各个依赖库间版本不兼容的问题,即在终端执行如下命令无法正确安装 Caffe 的依赖库:

$ pip install -r requirements.txt 


为了解决这个问题,我尝试去安装一些过时了的版本的依赖库,希望能借此解决不兼容的问题。但是,有些库的资源已经不太好找到了,因此,我最后使用了一种操作上比较简单的方法解决了这个问题。我们需要先安装一个 Ubuntu 18.04 系统,然后在终端执行如下命令:

$ sudo apt install caffe-cpu


然后,我们从 DeepCut 的官方 Github 上下载它的源代码。我们根据 README 中的教程,在终端依次执行如下命令:

$ pip3 install click
$ cd models/deepercut
$ ./download_models.sh


而在 run demo 时,我们不能完全依照教程中的步骤来执行。由于我们安装的是 cpu 版本的 Caffe,我们要在终端执行如下命令以运行 DeepCut demo:

$ cd python/pose
$ python3 ./pose_demo.py image.png --out_name=prediction --use_cpu


DeepCut 的关节点将储存在 ‘prediction.npz’ 文件中。接下来,我们要运行 SMPLify 的 ‘fit_3d.py’ 来测试我们的输入图片。

pyton3.x上的SMPLify运行_第4张图片

首先,我们可以留意到 ‘fit_3d.py’ 中有如下代码:

with open(join(data_dir, 'lsp_gender.csv')) as f:
    genders = f.readlines()


我们可以看到 SMPLify 需要读入一个保存测试图片性别的 csv 文件,因此,我们需要先为我们的测试图片创建一个这样的文件。

然后,SMPLify 需要读入 ‘est_joints.npz’ 文件,这个文件是一个 3x14xN 的 np 数组,其中,N 为测试图片的数目。在此,我们需要对如下代码进行一点修改:

est = np.load(join(data_dir, 'est_joints.npz'))['est_joints']


在 ‘prediction.npz’ 中,关节点被存放在 dict == ‘pose’ 中,我们要把代码修改成如下形式:

est = np.load(join(data_dir, 'prediction.npz'))['pose']


且外,由于我们的 prediction.npz 是 5x14 的 np 数组,我们还需要对其进行 reshape 才可以适用于 SMPLify 中:

est = est[0:3]
est = np.reshape(est, (-1, 14, 1))


至此,我们只需运行 ‘fit_3d.py’ 即可获得测试图片相对应的 SMPLify 预测结果:

pyton3.x上的SMPLify运行_第5张图片

显然,这个结果是存在明显的误差的,我们接下来需要定位误差产生的原因。

我们尝试使用 DeepCut 对 LSP dataset 的第一张图片进行预测:

pyton3.x上的SMPLify运行_第6张图片

然后将 DeepCut 的结果输入到 SMPLify(左图为自己运行 DeepCut 后得到的结果,右图为使用官方提供的 DeepCut 数据得到的结果):

pyton3.x上的SMPLify运行_第7张图片

我们发现即便使用 LSP dataset,我们也无法获得与 SMPLify 官方一样的结果。因此,我将自己运行 DeepCut 的输出与官方提供的 DeepCut 输出分别打印出来(上图为自己运行的结果,下图为官方提供的结果):

pyton3.x上的SMPLify运行_第8张图片

pyton3.x上的SMPLify运行_第9张图片

我们可以明显发现两者有较大的差别,因此,我们可以大胆推测目前阶段误差出现的原因是 DeepCut 的问题。

为了解决这个问题,需要先研究清楚 DeepCut 的论文,故目前还需要一点时间才能完成这个工作。我会在给课程期末项目收尾后,尽快完成这部分的工作。

你可能感兴趣的:(python)