风格迁移1-09:Liquid Warping GAN(Impersonator)-源码无死角解析(4)-hmr以及render

以下链接是个人关于Liquid Warping GAN(Impersonator)-姿态迁移,所有见解,如有错误欢迎大家指出,我会第一时间纠正。有兴趣的朋友可以加微信:a944284742相互讨论技术。若是帮助到了你什么,一定要记得点赞!因为这是对我最大的鼓励。
风格迁移1-00:Liquid Warping GAN(Impersonator)-目录-史上最新无死角讲解

前言

通过前面的博客,网络模型以及loss的总体计算,可以说是有了一定了解,那么现在我们分析下hmr以及render,其实呢,这个本来是不打算讲解的,因为这个其实不属于
Liquid Warping GAN的内容,作者也是直接使用别人训练好的模型,但是为了更加方便的理解论文,这里就带大家简单的过一遍,和论文串接起来。通过train.py,对其中的代码

        # 根据模式名字创建模型,默认使用impersonator模式进行训练,self._opt.model= impersonator_trainer
        self._model = ModelsFactory.get_by_name(self._opt.model, self._opt)

一路追踪,可以找到models/impersonator_trainer.py中的class Impersonator(BaseModel)类,进入其初始化函数调用的self._init_create_networks(),实现如下(只复制了核心代码):

        # body recovery Flow,构建body recovery网络,即hmr以及render
        self._bdr = BodyRecoveryFlow(opt=self._opt)

        # generator network,构建生成网络
        self._G = self._create_generator()
        
        # discriminator network,构建鉴别网络
        self._D = self._create_discriminator()

由这3个网络构成的统一模型,就是我们的,Liquid Warping GAN总体架构了,现在我们来看看上面3个部分的第一个部分,即hmr以及render。进入BodyRecoveryFlow。

代码注释

BodyRecoveryFlow的代码注释如下:

    def forward(self, src_img, ref_img, src_smpl, ref_smpl):
        # get smpl information,注意,这里的smpl来自于数据集的smpls中的pkl文件
        # 在训练的时候,是直接中获得得,也就是src_info以及ref_info的SMPL不是通过hmr估算出来的
        # 在测试的时候会使用hmr模型估算出来的结果
        # 其包含了theta[b,85] = pose[b,72] + shape[b,10] + cam[b,3]
        # cam[b,3],对应论文中的K, pose[b,72]对应论文的θ, shape[b,10]对应论文中的β
        # verts[b,6890,3]对应论文中的Nv
        # 最后还有j2d[b,19,2]与j3d[b,19,3]大概表示3D与2D视觉下,人体19个关键的空间坐标吧
        src_info = self._hmr.get_details(src_smpl)
        ref_info = self._hmr.get_details(ref_smpl)

        # process source inputs,在src_info['cam']的视角下,对src_info['verts']进行渲染
        # src_f2verts[b, 13776, 3, 2]对应论文中的Nf,对应于13776个坐标位置的mask
        src_f2verts, src_fim, _ = self._render.render_fim_wim(src_info['cam'], src_info['verts'])

        # 只取得原图的verts
        src_f2verts = src_f2verts[:, :, :, 0:2]

        # 把所有的y坐标乘以-1,应该是为了后续计算矩阵T的方便
        src_f2verts[:, :, :, 1] *= -1

        # src_cond[b,3,256,256],获得src img对应的verts所在位置坐标的mask
        src_cond, _ = self._render.encode_fim(src_info['cam'], src_info['verts'], fim=src_fim, transpose=True)

        # 获得mask掩码
        src_crop_mask = util.morph(src_cond[:, -1:, :, :], ks=3, mode='erode')

        #
        _, ref_fim, ref_wim = self._render.render_fim_wim(ref_info['cam'], ref_info['verts'])
        ref_cond, _ = self._render.encode_fim(ref_info['cam'], ref_info['verts'], fim=ref_fim, transpose=True)

        # 计算获得论文中的T矩阵
        T = self._render.cal_bc_transform(src_f2verts, ref_fim, ref_wim)


        # src_img经过T矩阵变化
        syn_img = F.grid_sample(src_img, T)

        # src input,input_G_src为论文中的Ift
        input_G_src = torch.cat([src_img * (1 - src_crop_mask), src_cond], dim=1)

        # tsf input,input_G_tsf为论文中的Isyn
        input_G_tsf = torch.cat([syn_img, ref_cond], dim=1)

        # bg input
        src_bg_mask = util.morph(src_cond[:, -1:, :, :], ks=15, mode='erode')

        # input_G_src_bg为论文中的Ibg,
        input_G_src_bg = torch.cat([src_img * src_bg_mask, src_bg_mask], dim=1)

        if self._opt.bg_both:
            ref_bg_mask = util.morph(ref_cond[:, -1:, :, :], ks=15, mode='erode')
            input_G_tsf_bg = torch.cat([ref_img * ref_bg_mask, ref_bg_mask], dim=1)
        else:
            input_G_tsf_bg = None

        # masks
        tsf_crop_mask = util.morph(ref_cond[:, -1:, :, :], ks=3, mode='erode')

        # 根据关键点分别获得头部,身体的box坐标
        head_bbox = self.cal_head_bbox(ref_info['j2d'])
        body_bbox = self.cal_body_bbox(ref_info['j2d'])

        return input_G_src_bg, input_G_tsf_bg, input_G_src, input_G_tsf, \
               T, src_crop_mask, tsf_crop_mask, head_bbox, body_bbox

大家观看代码从其前向传播看起,又兴趣的朋友可以去研究一下hmr以及render的细节,因为这是另外一个体系了,简单的介绍就到这里了,总的来说,我们主要是为了获得如下结果:

            # input_G_src_bg为论文中的Ibg,
            # input_G_src为论文中的Ift
            # input_G_tsf为论文中的Isyn
            # src_crop_mask为source图像的掩码,即人体部分像素为0,其余为1
            # tsf_crop_mask为reference图像的掩码,即人体部分像素为0,其余为1
            # T 和论文的T对应
            # head_bbox =  头部的bbox坐标
            # body_bbox = 身体的bbox坐标

获得了这些之后,就相当于得到了生成网络的输入,接下来要走的网络就是如下两个了:

        # generator network,构建生成网络
        self._G = self._create_generator()
        
        # discriminator network,构建鉴别网络
        self._D = self._create_discriminator()

公告

各位朋友,在这里表示抱歉,我发现此网络,虽然作者的构思很巧妙,但没有落地的价值,网络泛化能力较差,不能达到我预期的效果,还有很多需要改进的地方,所有暂时不打算深究下去了。如果以后本人有空闲时间,会把剩余的篇章都接上。如果需要查看其他的篇章,通过上面的链接即可,感谢各位朋友关注了,有你们一路的陪伴我真的很开心,也很骄傲!再见,其他项目再见。

你可能感兴趣的:(风格迁移)