IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 【NeRF】深度解读yenchenlin/nerf-pytorch项目 -> 正文阅读

[人工智能]【NeRF】深度解读yenchenlin/nerf-pytorch项目

前面我们已经成功地在yen项目上运行的我们自己的数据集。
但是效果比较差, 分析原因可能有以下两点。
1、 用于训练的数据集分辨率过低
2、超参数使用不巧当

Learning Object-Compositional Neural Radiance Field for Editable Scene Rendering论文中记录的效果
在这里插入图片描述
我们自己运行出来的效果。
在这里插入图片描述

目标

通过阅读yen源码,尝试回答以下问题或达成的目的。

  1. config.txt 文件中,各个参数的含义。
  2. 了解代码中重要变量的含义极其计算方式
  3. 调整分辨率前后通过COLMAP计算出来的poses和bds是一样的吗?
  4. 论文中那些定量的指标是哪里计算的,并且输出在哪里

变量探索

Render_poses

render_poses 和poses有什么关系?
显然load_llff.py 中的_load_data()函数仅返回获取的poses,bds和降低了分辨率之后的图像。
关于render_posesd的计算和数据集的划分是在load_llff_data() 中实现的。

def render_path_spiral(c2w, up, rads, focal, zdelta, zrate, rots, N):
    render_poses = []
    rads = np.array(list(rads) + [1.])
    hwf = c2w[:,4:5]
    
    for theta in np.linspace(0., 2. * np.pi * rots, N+1)[:-1]:
        c = np.dot(c2w[:3,:4], np.array([np.cos(theta), -np.sin(theta), -np.sin(theta*zrate), 1.]) * rads) 
        z = normalize(c - np.dot(c2w[:3,:4], np.array([0,0,-focal, 1.])))
        render_poses.append(np.concatenate([viewmatrix(z, up, c), hwf], 1))
    return render_poses
    

load_llff_data()的参数recenter?

recenter是对poses的调整。
内容如下:

	poses_ = poses+0
    bottom = np.reshape([0,0,0,1.], [1,4,声明里面也没有默认值,])
    c2w = poses_avg(poses)
    c2w = np.concatenate([c2w[:3,:4], bottom], -2)
    bottom = np.tile(np.reshape(bottom, [1,1,4]), [poses.shape[0],1,1])
    poses = np.concatenate([poses[:,:3,:4], bottom], -2)

    poses = np.linalg.inv(c2w) @ poses
    poses_[:,:3,:4] = poses[:,:3,:4]
    poses = poses_
    return poses

【?】调整了个啥,没有看出来?

所以准备在pycharm中配置解释器,通过设置断点来查看数据详情。

args.config

直到我把train()的全流程都走完了之后,才意识到一个重要的东西: 我应该先看args!!!

基本参数

 	parser.add_argument('--config', is_config_file=True, 
                        help='config file path') # 生成config.txt 文件
    parser.add_argument("--expname", type=str, 
                        help='experiment name') # 指定实验名称
    parser.add_argument("--basedir", type=str, default='./logs/', 
                        help='where to store ckpts and logs') #指定输出目录
    parser.add_argument("--datadir", type=str, default='./data/llff/fern', 
                        help='input data directory') # 指定数据目录

training options

	parser.add_argument("--netdepth", type=int, default=8, 
                        help='layers in network')   # 网络的深度(层数)
    parser.add_argument("--netwidth", type=int, default=256, 
                        help='channels per layer')  # 网络的宽度,也就是每一层的神经元个数
    parser.add_argument("--netdepth_fine", type=int, default=8, 
                        help='layers in fine network')
    parser.add_argument("--netwidth_fine", type=int, default=256, 
                        help='channels per layer in fine network')
    parser.add_argument("--N_rand", type=int, default=32*32*4,  # batch_size,光束的数量。
                        help='batch size (number of random rays per gradient step)')
    parser.add_argument("--lrate", type=float, default=5e-4,  # 学习率
                        help='learning rate')
    parser.add_argument("--lrate_decay", type=int, default=250,  # 指数学习率衰减(1000 步)
                        help='exponential learning rate decay (in 1000 steps)')
    parser.add_argument("--chunk", type=int, default=1024*32,  # 并行处理的光线数量,如果内存不足则减少
                        help='number of rays processed in parallel, decrease if running out of memory')
    parser.add_argument("--netchunk", type=int, default=1024*64,  # 通过网络并行发送的点数,如果内存不足则减少
                        help='number of pts sent through network in parallel, decrease if running out of memory')
    parser.add_argument("--no_batching", action='store_true',  # 一次只能从 1 张图像中获取随机光线
                        help='only take random rays from 1 image at a time')
    parser.add_argument("--no_reload", action='store_true',  # 不要从保存的 ckpt 重新加载权重
                        help='do not reload weights from saved ckpt')
    parser.add_argument("--ft_path", type=str, default=None,  # 为粗略网络重新加载特定权重 npy 文件
                        help='specific weights npy file to reload for coarse network')

rendering options

	parser.add_argument("--N_samples", type=int, default=64,  # 每条射线的粗样本数
                        help='number of coarse samples per ray')
    parser.add_argument("--N_importance", type=int, default=0, # 每条射线的附加精细样本数
                        help='number of additional fine samples per ray')
    parser.add_argument("--perturb", type=float, default=1., # 设置为 0. 无抖动,1. 抖动
                        help='set to 0. for no jitter, 1. for jitter')
    parser.add_argument("--use_viewdirs", action='store_true', 
                        help='use full 5D input instead of 3D')
    parser.add_argument("--i_embed", type=int, default=0,  #为默认位置编码设置 0,为无设置 -1
                        help='set 0 for default positional encoding, -1 for none')
    parser.add_argument("--multires", type=int, default=10,  # 多分辨率。 位置编码的最大频率的 log2(3D 位置)
                        help='log2 of max freq for positional encoding (3D location)')
    parser.add_argument("--multires_views", type=int, default=4,  # 位置编码的最大频率的 log2(2D 方向)
                        help='log2 of max freq for positional encoding (2D direction)')
    parser.add_argument("--raw_noise_std", type=float, default=0.,  #  噪音方差
                        help='std dev of noise added to regularize sigma_a output, 1e0 recommended')

    parser.add_argument("--render_only", action='store_true',  # 不要优化,重新加载权重和渲染 render_poses 路径
                        help='do not optimize, reload weights and render out render_poses path')
    parser.add_argument("--render_test", action='store_true',  # 渲染测试集而不是 render_poses 路径
                        help='render the test set instead of render_poses path')
    parser.add_argument("--render_factor", type=int, default=0,  # 下采样因子以加快渲染速度,设置为 4 或 8 用于快速预览
                        help='downsampling factor to speed up rendering, set 4 or 8 for fast preview')

training options

	parser.add_argument("--precrop_iters", type=int, default=0, # 对主要作物进行培训的步骤数
                        help='number of steps to train on central crops')
    parser.add_argument("--precrop_frac", type=float, # ?
                        default=.5, help='fraction of img taken for central crops') 

dataset options

 	parser.add_argument("--dataset_type", type=str, default='llff', 
                        help='options: llff / blender / deepvoxels')
    parser.add_argument("--testskip", type=int, default=8,  # 将从测试/验证集中加载 1/N 图像,这对于像 deepvoxels 这样的大型数据集很有用
                        help='will load 1/N images from test/val sets, useful for large datasets like deepvoxels')

加载llff类型数据集的参数

	parser.add_argument("--factor", type=int, default=8,  # LLFF 图像的下采样因子
                        help='downsample factor for LLFF images')
    parser.add_argument("--no_ndc", action='store_true',   #如果是store_false,则默认值是True,如果是store_true,则默认值是False
                        help='do not use normalized device coordinates (set for non-forward facing scenes)')  #不要使用标准化的设备坐标(为非前向场景设置
    parser.add_argument("--lindisp", action='store_true',# 在视差而不是深度中线性采样 ?
                        help='sampling linearly in disparity rather than depth')
    parser.add_argument("--spherify", action='store_true',   # 球体的
                        help='set for spherical 360 scenes') # 设置为球形 360 场景
    parser.add_argument("--llffhold", type=int, default=8,  # 将每 1/N 个图像作为 LLFF 测试集,论文使用 8
                        help='will take every 1/N images as LLFF test set, paper uses 8')

logging/saving options

	parser.add_argument("--i_print",   type=int, default=100, 
                        help='frequency of console printout and metric loggin')
    parser.add_argument("--i_img",     type=int, default=500, 
                        help='frequency of tensorboard image logging')
    parser.add_argument("--i_weights", type=int, default=10000, 
                        help='frequency of weight ckpt saving')
    parser.add_argument("--i_testset", type=int, default=50000, 
                        help='frequency of testset saving')
    parser.add_argument("--i_video",   type=int, default=50000, 
                        help='frequency of render_poses video saving')

Debug 调试获取数据情况。

我们测试的是desk2这个数据集。
其中包含了151张图像。

load_llff.py _load_data()

  • poses_bounds.npy 提取的原始数据 poses_arr , size = 151 x 17 .
    在这里插入图片描述

  • poses = poses_arr[:, :-2].reshape([-1, 3, 5]).transpose([1,2,0]) (3, 5, 151), poses[0] ↓
    在这里插入图片描述

  • bds = poses_arr[:, -2:].transpose([1,0]) (2,151)
    在这里插入图片描述

  • img0 = [os.path.join(basedir, 'images', f) for f in sorted(os.listdir(os.path.join(basedir, 'images'))) \ if f.endswith('JPG') or f.endswith('jpg') or f.endswith('png')][0] 查看单张图片的情况。'.img0 = /data/img_desk2/images/0000.jpg'

  • sh = imageio.imread(img0).shape 单张图片的shape, (4344, 5792, 3) .

  • 函数 创建目标分辨率的数据集, 无返回。

  • imgfiles list类型,包含了目标数据的路径。

  • 再次获取图片的shape ( sh = (543,724,3))

  • poses[:2, 4, :] = np.array(sh[:2]).reshape([2, 1]) shape(3,5,151) poses[0] ↓
    在这里插入图片描述

  • poses[2, 4, :] = poses[2, 4, :] * 1./factor shape(3,5,151) poses[0] ↓
    在这里插入图片描述

  • imgs = imgs = [imread(f)[...,:3]/255. for f in imgfiles] 读取所有的图像数据,并把值控制在0-1之间。
    在这里插入图片描述

  • imgs = np.stack(imgs, -1) 转为了array类型,shape (543, 727,3,1,151)
    在这里插入图片描述

  • return poses, bds, imgs

load_llff.py _minify()

这个函数主要负责创建 目标分别率的数据集。

  • 检查目标路径是否存在,若存在直接return。
args = ' '.join(['mogrify', '-resize', resizearg, '-format', 'png', '*.{}'.format(ext)])
        print(args)
        os.chdir(imgdir) # 修改当前工作目录
        check_output(args, shell=True)
        os.chdir(wd)
  • 通过以上操作,创建了目标数据集。

load_llff.py load_llff_datad()

  • poses, bds, imgs = _load_data(basedir, factor=factor)
	poses = np.concatenate([poses[:, 1:2, :], -poses[:, 0:1, :], poses[:, 2:, :]], 1)
    poses = np.moveaxis(poses, -1, 0).astype(np.float32)
    imgs = np.moveaxis(imgs, -1, 0).astype(np.float32)
    images = imgs
    bds = np.moveaxis(bds, -1, 0).astype(np.float32)
  • 接下来对数据进行如上的处理,得到的结果如下:

    • bds 是 151 *2 规模的。
      在这里插入图片描述
    • images 是 (151,543,727,3) 分别对应(图片张数、高、宽、通道)
    • poses 是(151,3,5),也就是说,对于每张图片,它的opose是个 3*5的数据。
      在这里插入图片描述
  • sc = 1. if bd_factor is None else 1./(bds.min() * bd_factor) sc :进行边界放缩的比例, = 0.859302

  • poses 进行边界放缩之后 即poses[:,:3,3] *= sc,如下
    在这里插入图片描述

  • bds *=sc 之后,所有的值都缩小了。 即边界缩小了。
    在这里插入图片描述

    if recenter:
        poses = recenter_poses(poses)
  • 执行poses = recenter_poses(poses) 之后,poses (shape 151,3,5)的值如下: 这个操作修改了前四列的值,保持最后一列值不变。 (要弄清楚每列的含义)。 最后一列是图像的(高,宽,焦距)
    在这里插入图片描述
		c2w = poses_avg(poses)  # 3x5
        print('recentered', c2w.shape)
        print(c2w[:3,:4])

        ## Get spiral
        # Get average pose
        up = normalize(poses[:, :3, 1].sum(0))   # 3x1

        # Find a reasonable "focus depth" for this dataset
        close_depth, inf_depth = bds.min()*.9, bds.max()*5. # 1.19999, 1116.4336
        dt = .75
        mean_dz = 1./(((1.-dt)/close_depth + dt/inf_depth))  # 4.656
        focal = mean_dz  #焦距

        # Get radii for spiral path  半径
        shrink_factor = .8
        zdelta = close_depth * .2
        tt = poses[:,:3,3] # ptstocam(poses[:3,3,:].T, c2w).T
        rads = np.percentile(np.abs(tt), 90, 0)  # 求90百分位的数值
        c2w_path = c2w
        N_views = 120
        N_rots = 2
        if path_zflat:  # false
#             zloc = np.percentile(tt, 10, 0)[2]
            zloc = -close_depth * .1
            c2w_path[:3,3] = c2w_path[:3,3] + zloc * c2w_path[:3,2]
            rads[2] = 0.
            N_rots = 1
            N_views/=2

        # Generate poses for spiral path
        render_poses = render_path_spiral(c2w_path, up, rads, focal, zdelta, zrate=.5, rots=N_rots, N=N_views)
  • 通过以上代码获取 render_poses,其中

    • c2w = poses_avg(poses) shapa( 3,5 ) , 相当于汇合了所有的图像,值如下:
      在这里插入图片描述

    • 中间数值如下:
      在这里插入图片描述

    • tt = poses[:,:3,3],取所有poses的三列,shape (151,3)
      在这里插入图片描述

    • rads = np.percentile(np.abs(tt), 90, 0) # 求90百分位的数值
      在这里插入图片描述

    • render_poses = render_path_spiral(c2w_path, up, rads, focal, zdelta, zrate=.5, rots=N_rots, N=N_views) 是个list,长度为120 (由N_view确定),每个元素为(3,5), 这一点和poses是一样的。

  • render_poses = np.array(render_poses).astype(np.float32) 转为array,shape (102,3,5), render_poses[0]
    在这里插入图片描述

  • 再次计算c2w c2w = poses_avg(poses). 和之前的对比了一下,数值上是一模一样的。
    在这里插入图片描述

  • dists = np.sum(np.square(c2w[:3,3] - poses[:,:3,3]), -1) shape 151
    在这里插入图片描述

  • i_test = np.argmin(dists) # 取值最小的索引 值为83,HOLDOUT view is 83。

  • return images, poses, bds, render_poses, i_test。 此时 images (151, 543,724,3), poses (151,3,5) ,bds (151,2) render_poses( 120,3,5) , i_test = 83

load_llff.py render_path_spiral()

  • render_path_spiral() 中 的hwf = c2w[:,4:5]
    在这里插入图片描述
  • 获得的第一个render_poses 。 render_poses.append(np.concatenate([viewmatrix(z, up, c), hwf], 1))
    在这里插入图片描述
  • return render_poses # 类型是list

run_nerf.py train()

  • images, poses, bds, render_poses, i_test = load_llff_data(args.datadir, args.factor, recenter=True, bd_factor=.75, spherify=args.spherify) 此时 images (151, 543,724,3), poses (151,3,5) ,bds (151,2) render_poses( 120,3,5) , i_test = 83.

  • hwf = poses[0,:3,-1]
    在这里插入图片描述

  • poses = poses[:,:3,:4] , 下面是poses[0]
    在这里插入图片描述

  • Loaded llff (151, 543, 724, 3) (120, 3, 5) [543. 724. 537.2688] ./data/img_desk2

  • Auto LLFF holdout i_test = np.arange(images.shape[0])[::args.llffhold]之后,i_test 变成了下面这个样子。 也就是说,获取了多个测试样本。 ,声明里面也没有默认值,
    在这里插入图片描述

		i_val = i_test  # 验证集和测试集相同
        i_train = np.array([i for i in np.arange(int(images.shape[0])) if
                        (i not in i_test and i not in i_val)])  # 把剩下的部分当做训练集
  • 通过上述代码获取验证集和训练集。
  • 定义边界 near = 0. far = 1.
    H, W, focal = hwf
    H, W = int(H), int(W)
    hwf = [H, W, focal]
  • 重新获取hwf的值, list 类型, [543, 724, 537.2688]
    if K is None: # 前文自己定义为空的。 
        K = np.array([
            [focal, 0, 0.5*W],
            [0, focal, 0.5*H],
            [0, 0, 1]
        ])
  • 定义k, shape (3,3), 值如下:
    在这里插入图片描述

Create log dir and copy the config file

  • os.makedirs(os.path.join(basedir, expname), exist_ok=True) 创建log目录
  • f = os.path.join(basedir, expname, 'args.txt') 参数文件 args.txt
    with open(f, 'w') as file:
        for arg in sorted(vars(args)):
            attr = getattr(args, arg)
            file.write('{} = {}\n'.format(arg, attr))
  • 把所有的参数都写到文件里面。

Create nerf model

  • render_kwargs_train, render_kwargs_test, start, grad_vars, optimizer = create_nerf(args) 创建模型。
    • start= 0
    • optimizer
      在这里插入图片描述
    • render_kwargs_test 是个dist 类型,9个元素
      在这里插入图片描述
    • render_kwargs_train 也是个dist类型, 9个元素。
      在这里插入图片描述
    • grad_vars 是个list,长度 为48
  • global_step = start
  • bds_dict = { 'near' : near, 'far' : far, } 表示为字典。
  • render_kwargs_train.update(bds_dict) 更新render_kwargs_train,字典的update操作, 更新之后,render_kwargs_train 变为11个元素的字典。即在末尾添加了'near' = near, 'far' = far,
  • render_kwargs_test.update(bds_dict)

Move testing data to GPU

  • render_poses = torch.Tensor(render_poses).to(device)

Prepare raybatch tensor if batching random rays

use_batching = true 的情况下

  • rays = np.stack([get_rays_np(H, W, K, p) for p in poses[:,:3,:4]], 0) 获取光束。从函数来看,和poses有关。 shape(151,2,543,724,3) ,也就是[N, ro+rd, H, W, 3]
  • rays_rgb = np.concatenate([rays, images[:,None]], 1), shape (151, 3, 543, 724, 3), 也就是[N, H, W, ro+rd+rgb, 3]。
  • rays_rgb = np.transpose(rays_rgb, [0,2,3,1,4]) 调换了位置,[N, H, W, ro+rd+rgb, 3],shape(151, 543, 724, 3, 3)
  • rays_rgb = np.stack([rays_rgb[i] for i in i_train], 0) 只获取train images的部分。 shape(132, 543, 724, 3, 3) ,总的数量由151 变为了 132。
  • rays_rgb = np.reshape(rays_rgb, [-1,3,3]) [(N-1)HW, ro+rd+rgb, 3],shape (51893424, 3, 3) 。 这就相当于获得了51893424个光束。
  • np.random.shuffle(rays_rgb) 打乱这个光束的顺序。 shape不变。

Move training data to GPU

    if use_batching:
        images = torch.Tensor(images).to(device)
    poses = torch.Tensor(poses).to(device)
    if use_batching:
        rays_rgb = torch.Tensor(rays_rgb).to(device)

开始进入训练的迭代

start = start + 1
    for i in trange(start, N_iters):
Sample random ray batch

if use_batching

  • batch = rays_rgb[i_batch:i_batch+N_rand] # [B, 2+1, 3*?] N_rand = 1024, batch 的shape torch.Size([1024, 3, 3])
  • batch = torch.transpose(batch, 0, 1) 转换0和1维,shape torch.Size([3, 1024, 3]) 也就是说,[od+rd+rgb, 1024, 3], 最后一个3还是表示的通道。
  • batch_rays, target_s = batch[:2], batch[2]batch_rays shape torch.Size([2, 1024, 3]),也就是[od+rd, 1024, 3]。 target_s shape torch.Size([1024, 3]) 对应的是rgb。

render

  • rgb, disp, acc, extras = render(H, W, K, chunk=args.chunk, rays=batch_rays, verbose=i < 10, retraw=True, **render_kwargs_train) 返回渲染出的 一个 batch的 rgb ,disp(密度),acc, extras。 (量化指标。)
    • rgb shape torch.Size([1024, 3]) 刚好可以好target_s 对应上。
    • disp shape 1024,和1024个光束对应。
    • acc shape 1024, 对应1024个光束
    • extras 是一个dict,含有5个元素,具体如下:
      在这里插入图片描述
  • img_loss = img2mse(rgb, target_s) 求rgb损失, 值为0.0663。 其中img2mse = lambda x, y : torch.mean((x - y) ** 2) 也就是均方误差MSE
  • trans = extras['raw'][...,-1] shape torch.Size([1024, 128]) 这个值,后面好像并没有用到。
  • psnr = mse2psnr(img_loss) , 值为11.7821 。 其中mse2psnr = lambda x : -10. * torch.log(x) / torch.log(torch.Tensor([10.]))
        if 'rgb0' in extras:
            img_loss0 = img2mse(extras['rgb0'], target_s)
            loss = loss + img_loss0
            psnr0 = mse2psnr(img_loss0)
  • rgb0 是extras的一个元素, 这里用extras[‘rgb0’]和target_s 求了损失,并把这个损失加在了整体的损失上,也就是说,loss = img_loss+img_loss0.
		loss.backward()
        optimizer.step()

        # NOTE: IMPORTANT!
        ###   update learning rate   ###
        decay_rate = 0.1
        decay_steps = args.lrate_decay * 1000
        new_lrate = args.lrate * (decay_rate ** (global_step / decay_steps))
        for param_group in optimizer.param_groups:
            param_group['lr'] = new_lrate
  • 以上是模型training的常规操作。

保存checkpoint

        if i%args.i_weights==0:
            path = os.path.join(basedir, expname, '{:06d}.tar'.format(i))
            torch.save({
                'global_step': global_step,
                'network_fn_state_dict': render_kwargs_train['network_fn'].state_dict(),
                'network_fine_state_dict': render_kwargs_train['network_fine'].state_dict(),
                'optimizer_state_dict': optimizer.state_dict(),
            }, path)
            print('Saved checkpoints at', path)  # 保存checkpoint。
  • 保存形式为tar 压缩包, 内容是一个字典,包含以上字段。

输出mp4 视频

 if i%args.i_video==0 and i > 0:
            # Turn on testing mode
            with torch.no_grad():
                rgbs, disps = render_path(render_poses, hwf, K, args.chunk, render_kwargs_test)
            print('Done, saving', rgbs.shape, disps.shape)
            moviebase = os.path.join(basedir, expname, '{}_spiral_{:06d}_'.format(expname, i))
            imageio.mimwrite(moviebase + 'rgb.mp4', to8b(rgbs), fps=30, quality=8)
            imageio.mimwrite(moviebase + 'disp.mp4', to8b(disps / np.max(disps)), fps=30, quality=8)
  • 这里可以看出来,render_pose 是可以用来合成360旋转的视频的。
  • 函数render_path()返回的是rgb,和对应的密度disps。
  • 看到这里明白spiral的 含义了。指的是视频中的螺旋旋转。
  • to8b 具体实现为to8b = lambda x : (255*np.clip(x,0,1)).astype(np.uint8)

保存测试数据集

       if i%args.i_testset==0 and i > 0:
            testsavedir = os.path.join(basedir, expname, 'testset_{:06d}'.format(i))
            os.makedirs(testsavedir, exist_ok=True)
            print('test poses shape', poses[i_test].shape)
            with torch.no_grad():
                render_path(torch.Tensor(poses[i_test]).to(device), hwf, K, args.chunk, render_kwargs_test, gt_imgs=images[i_test], savedir=testsavedir)
            print('Saved test set')
  • 可以看出,主要还是用的render_path() 函数,但给的参数和上面不同,后面我们再具体了解这个函数 。

render _only

首先,这个参数,要在运行命令中加, --render_only

    if args.render_only:
        print('RENDER ONLY')
        with torch.no_grad():
            if args.render_test:
                # render_test switches to test poses
                images = images[i_test]
            else:
                # Default is smoother render_poses path
                images = None

            testsavedir = os.path.join(basedir, expname, 'renderonly_{}_{:06d}'.format('test' if args.render_test else 'path', start))
            os.makedirs(testsavedir, exist_ok=True)
            print('test poses shape', render_poses.shape)

            rgbs, _ = render_path(render_poses, hwf, K, args.chunk, render_kwargs_test, gt_imgs=images, savedir=testsavedir, render_factor=args.render_factor)
            print('Done rendering', testsavedir)
            imageio.mimwrite(os.path.join(testsavedir, 'video.mp4'), to8b(rgbs), fps=30, quality=8)

            return
  • 这种情况下,还需要判断是否render_test, 也就是是否指定render的对象。 如果是,images 就是所有的测试样本,否则渲染的是一个路径。
  • 通过rgbs, _ = render_path(render_poses, hwf, K, args.chunk, render_kwargs_test, gt_imgs=images, savedir=testsavedir, render_factor=args.render_factor) 返回的rgb
  • 然后通过imageio.mimwrite(os.path.join(testsavedir, 'video.mp4'), to8b(rgbs), fps=30, quality=8)转为视频。

至此,这个train() 函数就完结了。

下面我们需要以此了解train() 中调用的几个重要函数。

run_nerf.py create_nerf()

函数调用方法render_kwargs_train, render_kwargs_test, start, grad_vars, optimizer = create_nerf(args)
Instantiate NeRF’s MLP model.

- 
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:11:32  更:2022-04-04 12:16:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 11:28:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码