范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

100行Pytorch代码实现三维重建技术神经辐射场(NeRF)

  来源:DeepHub IMBA本文约3300字,建议阅读10+分钟本文通过100行的Pytorch代码实现最初的 NeRF 论文。
  提起三维重建技术,NeRF是一个绝对绕不过去的名字。这项逆天的技术,一经提出就被众多研究者所重视,对该技术进行深入研究并提出改进已经成为一个热点。不到两年的时间,NeRF及其变种已经成为重建领域的主流。
  NeRF全称为Neural Radiance Fields(神经辐射场),是一项利用多目图像重建三维场景的技术。该项目的作者来自于加州大学伯克利分校,Google研究院,以及加州大学圣地亚哥分校。NeRF使用一组多目图作为输入,通过优化一个潜在连续的体素场景方程来得到一个完整的三维场景。
  该方法使用一个全连接深度网络来表示场景,使用的输入是一个单连通的5D坐标(空间位置x,y,z以及观察视角θ,),输出为一个体素场景,可以以任意视角查看,并通过体素渲染技术,生成需要视角的照片。该方法同样支持视频合成。
  该方法是一个基于体素重建的方法,通过在多幅图片中的五维坐标建立一个由粗到细的对应,进而恢复出原始的三维体素场景。
  NeRF 和神经渲染的基本概念
  Rendering
  渲染是从 3D 模型创建图像的过程。该模型将包含纹理、阴影、阴影、照明和视点等特征,渲染引擎的作用是处理这些特征以创建逼真的图像。
  三种常见的渲染算法类型是光栅化,它根据模型中的信息以几何方式投影对象,没有光学效果;光线投射,使用基本的光学反射定律从特定角度计算图像;和光线追踪,它使用蒙特卡罗技术在更短的时间内获得逼真的图像。光线追踪用于提高 NVIDIA GPU 中的渲染性能。
  Volume Rendering
  立体渲染使能够创建 3D 离散采样数据集的 2D 投影。
  对于给定的相机位置,立体渲染算法为空间中的每个体素获取 RGBα(红色、绿色、蓝色和 Alpha 通道),相机光线通过这些体素投射。RGBα 颜色转换为 RGB 颜色并记录在 2D 图像的相应像素中。对每个像素重复该过程,直到呈现整个 2D 图像。
  View Synthesis
  视图合成与立体渲染相反——它涉从一系列 2D 图像创建 3D 视图。这可以使用一系列从多个角度显示对象的照片来完成,创建对象的半球平面图,并将每个图像放置在对象周围的适当位置。视图合成函数尝试在给定一系列描述对象不同视角的图像的情况下预测深度。
  NeRF是如何工作的
  NeRF使用一组稀疏的输入视图来优化连续的立体场景函数。这种优化的结果是能够生成复杂场景的新视图。
  NeRF使用一组多目图作为输入:
  输入为一个单连通的5D坐标(空间位置x,y,z以及观察视角(θ; Φ)
  输出为一个体素场景 c = (r; g; b) 和体积密度 (α)。
  下面是如何从一个特定的视点生成一个NeRF:
  通过移动摄像机光线穿过场景生成一组采样的3D点  将采样点及其相应的2D观察方向输入神经网络,生成密度和颜色的输出集  通过使用经典的立体渲染技术,将密度和颜色累积到2D图像中
  上述过程深度的全连接、多层感知器(MLP)进行优化,并且不需要使用卷积层。它使用梯度下降来最小化每个观察到的图像和从表示中呈现的所有相应视图之间的误差。
  Pytorch代码实现
  渲染
  神经辐射场的一个关键组件,是一个可微分渲染,它将由NeRF模型表示的3D表示映射到2D图像。该问题可以表述为一个简单的重构问题。
  这里的A是可微渲染,x是NeRF模型,b是目标2D图像。
  代码如下:
  def render_rays(nerf_model, ray_origins, ray_directions, hn=0, hf=0.5, nb_bins=192):       device = ray_origins.device       t = torch.linspace(hn, hf, nb_bins, device=device).expand(ray_origins.shape[0], nb_bins)       # Perturb sampling along each ray.       mid = (t[:, :-1] + t[:, 1:]) / 2.       lower = torch.cat((t[:, :1], mid), -1)       upper = torch.cat((mid, t[:, -1:]), -1)       u = torch.rand(t.shape, device=device)       t = lower + (upper - lower) * u  # [batch_size, nb_bins]       delta = torch.cat((t[:, 1:] - t[:, :-1], torch.tensor([1e10], device=device).expand(ray_origins.shape[0], 1)), -1)          x = ray_origins.unsqueeze(1) + t.unsqueeze(2) * ray_directions.unsqueeze(1)   # [batch_size, nb_bins, 3]       ray_directions = ray_directions.expand(nb_bins, ray_directions.shape[0], 3).transpose(0, 1)          colors, sigma = nerf_model(x.reshape(-1, 3), ray_directions.reshape(-1, 3))       colors = colors.reshape(x.shape)       sigma = sigma.reshape(x.shape[:-1])          alpha = 1 - torch.exp(-sigma * delta)  # [batch_size, nb_bins]       weights = compute_accumulated_transmittance(1 - alpha).unsqueeze(2) * alpha.unsqueeze(2)       c = (weights * colors).sum(dim=1)  # Pixel values       weight_sum = weights.sum(-1).sum(-1)  # Regularization for white background       return c + 1 - weight_sum.unsqueeze(-1)
  渲染将NeRF模型和来自相机的一些光线作为输入,并使用立体渲染返回与每个光线相关的颜色。
  代码的初始部分使用分层采样沿射线选择3D点。然后在这些点上查询神经辐射场模型(连同射线方向)以获得密度和颜色信息。模型的输出可以用蒙特卡罗积分计算每条射线的线积分。
  累积透射率(论文中Ti)用下面的专用函数中单独计算。
  def compute_accumulated_transmittance(alphas):       accumulated_transmittance = torch.cumprod(alphas, 1)       return torch.cat((torch.ones((accumulated_transmittance.shape[0], 1), device=alphas.device),                         accumulated_transmittance[:, :-1]), dim=-1) NeFR
  我们已经有了一个可以从3D模型生成2D图像的可微分模拟器,下面就是实现NeRF模型。
  根据上面的介绍,NeRF非常的复杂,但实际上NeRF模型只是多层感知器(MLPs)。但是具有ReLU激活函数的mlp倾向于学习低频信号。当试图用高频特征建模物体和场景时,这就出现了一个问题。为了抵消这种偏差并允许模型学习高频信号,使用位置编码将神经网络的输入映射到高维空间。
  class NerfModel(nn.Module):      def __init__(self, embedding_dim_pos=10, embedding_dim_direction=4, hidden_dim=128):          super(NerfModel, self).__init__()            self.block1 = nn.Sequential(nn.Linear(embedding_dim_pos * 6 + 3, hidden_dim), nn.ReLU(),                                      nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),                                      nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),                                      nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), )            self.block2 = nn.Sequential(nn.Linear(embedding_dim_pos * 6 + hidden_dim + 3, hidden_dim), nn.ReLU(),                                      nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),                                      nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),                                      nn.Linear(hidden_dim, hidden_dim + 1), )            self.block3 = nn.Sequential(nn.Linear(embedding_dim_direction * 6 + hidden_dim + 3, hidden_dim // 2), nn.ReLU(), )          self.block4 = nn.Sequential(nn.Linear(hidden_dim // 2, 3), nn.Sigmoid(), )            self.embedding_dim_pos = embedding_dim_pos          self.embedding_dim_direction = embedding_dim_direction          self.relu = nn.ReLU()        @staticmethod      def positional_encoding(x, L):          out = [x]          for j in range(L):              out.append(torch.sin(2 ** j * x))              out.append(torch.cos(2 ** j * x))          return torch.cat(out, dim=1)        def forward(self, o, d):          emb_x = self.positional_encoding(o, self.embedding_dim_pos)          emb_d = self.positional_encoding(d, self.embedding_dim_direction)          h = self.block1(emb_x)          tmp = self.block2(torch.cat((h, emb_x), dim=1))          h, sigma = tmp[:, :-1], self.relu(tmp[:, -1])          h = self.block3(torch.cat((h, emb_d), dim=1))          c = self.block4(h)          return c, sigma
  训练
  训练循环也很简单,因为它也是监督学习。我们可以直接最小化预测颜色和实际颜色之间的L2损失。
  def train(nerf_model, optimizer, scheduler, data_loader, device="cpu", hn=0, hf=1, nb_epochs=int(1e5),             nb_bins=192, H=400, W=400):       training_loss = []       for _ in tqdm(range(nb_epochs)):           for batch in data_loader:               ray_origins = batch[:, :3].to(device)               ray_directions = batch[:, 3:6].to(device)               ground_truth_px_values = batch[:, 6:].to(device)                  regenerated_px_values = render_rays(nerf_model, ray_origins, ray_directions, hn=hn, hf=hf, nb_bins=nb_bins)               loss = ((ground_truth_px_values - regenerated_px_values) ** 2).sum()                  optimizer.zero_grad()               loss.backward()               optimizer.step()               training_loss.append(loss.item())           scheduler.step()              for img_index in range(200):               test(hn, hf, testing_dataset, img_index=img_index, nb_bins=nb_bins, H=H, W=W)          return training_loss 测试
  训练过程完成,NeRF模型就可以用于从任何角度生成图像。测试函数通过使用来自测试图像的射线数据集进行操作,然后使用渲染函数和优化的NeRF模型为这些射线生成图像。
  @torch.no_grad()   def test(hn, hf, dataset, chunk_size=10, img_index=0, nb_bins=192, H=400, W=400):       ray_origins = dataset[img_index * H * W: (img_index + 1) * H * W, :3]       ray_directions = dataset[img_index * H * W: (img_index + 1) * H * W, 3:6]          data = []       for i in range(int(np.ceil(H / chunk_size))):           ray_origins_ = ray_origins[i * W * chunk_size: (i + 1) * W * chunk_size].to(device)           ray_directions_ = ray_directions[i * W * chunk_size: (i + 1) * W * chunk_size].to(device)              regenerated_px_values = render_rays(model, ray_origins_, ray_directions_, hn=hn, hf=hf, nb_bins=nb_bins)           data.append(regenerated_px_values)       img = torch.cat(data).data.cpu().numpy().reshape(H, W, 3)          plt.figure()       plt.imshow(img)       plt.savefig(f"novel_views/img_{img_index}.png", bbox_inches="tight")       plt.close() 所有的部分都可以很容易地组合起来。  if __name__ == "main":       device = "cuda"       training_dataset = torch.from_numpy(np.load("training_data.pkl", allow_pickle=True))       testing_dataset = torch.from_numpy(np.load("testing_data.pkl", allow_pickle=True))       model = NerfModel(hidden_dim=256).to(device)       model_optimizer = torch.optim.Adam(model.parameters(), lr=5e-4)       scheduler = torch.optim.lr_scheduler.MultiStepLR(model_optimizer, milestones=[2, 4, 8], gamma=0.5)          data_loader = DataLoader(training_dataset, batch_size=1024, shuffle=True)       train(model, model_optimizer, scheduler, data_loader, nb_epochs=16, device=device, hn=2, hf=6, nb_bins=192, H=400,             W=400) 这样一个简单的NeRF就完成了,看看效果:
  希望本文对你有所帮助,如果你对NeRF感兴趣可以看看这个项目:
  https://github.com/kwea123/nerf_pl/
  学术分享,转自DeepHub IMBA,侵删

直来直往的郭艾伦,或成CBA的无冕之王本赛季的CBA联赛已经在4月26日落下了帷幕,我的家乡球队,辽宁本钢队,终于在四年后再一次捧起了总冠军至尊鼎。今年是辽宁男篮大丰收的一年,和四年前一模一样的全运会和联赛的双冠军。作一夜3消息!宏远官方喜讯,郭艾伦顶薪留队,莫兰德喝白酒喝蒙北京时间4月29日,五一劳动节假期将至,小编在这里祝各位假期愉快!适逢广大劳动者的节日,中华全国总工会举行了全国五一劳动节表彰大会。值得一提的是,十一冠王广东宏远在这次表彰大会上获好消息!杜锋领取五一大奖,易建联开始创业,徐杰成为重要嘉宾问如何每天都能收到如此有趣的体育原创资讯?回答只需轻点右上角的关注按钮就能实现梦想。辽宁男篮真给力,40横扫广厦夺冠后给球迷预留了一个美好的五一长假,按照赛程,如果双方打到抢七大战压哨买断?湖人或捡漏签下2611昔日全明星,詹皇这下轻松了湖人本赛季成为西部最让人感到失望的球队,没能展现出应有的实力,更没有展现出韧性,遇到实力强的球队时几乎是毫无还手之力,一波连败后彻底失去了进入季后赛的机会。然而这一切似乎跟詹姆斯没体操女神张豆豆与孙杨恋情曝光?女方发文暧昧不清,如今迎来反转近日有网友爆料称,他在山西省清徐县偶遇了张豆豆和孙杨,并且这个地点也是张豆豆的家乡,所以这条消息一出,立刻就有网友们猜测二人是不是在一起了,随后张豆豆就在社交平台上发文心里藏着小星抗衰老肽复杂了!不,其实很简单近年来,雅诗兰黛兰蔻香奈儿迪奥以及SKII等掀起胜肽护肤热潮,以胜肽为主要活性成分的护肤品在国内大火。驻扎知乎小红书B站的成分党大V更是对胜肽类抗衰老产品赞赏有加,甚至捧高胜肽踩低青椒和它俩是绝配,5分钟出锅便宜又鲜美,简单又营养,总吃不腻一年之计在于春,春天大地春回,阳气上升,不过气候变化无常,这时我们要讲究科学合理饮食,适时调养好自己的身体。春季饮食养生,更适宜清淡些,油腻和油炸的食物尽量少吃,应该多吃一些蔬菜瓜衬衫怎么穿更有高级感?建议学学三木博主的穿搭,轻松拥有好气质今天穿什么衬衫的风格是很丰富的,虽然很多人觉得衬衫在平时生活中难以穿出高级感,但只要懂得选择款式,并且结合一些时尚的搭配技巧,就能够轻松穿的时髦又高级。比如,三木博主这些精彩的造型山口百惠无惧身材发福,穿衬衫配九分裤依然时髦,优雅老去也挺美明天穿什么呢?这个问题一定是很多爱美女性的烦恼。永远觉得衣橱里少一件衣服是女人的常态。不过还是有一些百搭经典不过时的单品可以让我们去反复琢磨,穿出不一样的美的。衬衫就是其中的一员。好吃不胖的西蓝花炒香菇,超简单的低脂餐哈喽,大家好呀!今天分享简单清爽好吃的西兰花炒香菇,做法简单,口感鲜美香菇嫩滑,喜欢的一起来试试吧食材灵光一闪西兰花半朵香菇8朵蒜末一勺做法灵光一闪1。西兰花洗净手撕小朵香菇切片,无配饰不时髦,想要精致过夏天的,可以从这三方面下手很多小姐姐可能不知道,春夏天穿衣取胜的关键并不在单品款式颜色和整体搭配上,只要把更多注意力放在细节处理上,均可保各位今年春夏天无忧。细节问题大大小小的有很多,今天我们学习的是如何利
曝华为Mate50年内无望发布,Mate40沦为百元机,花粉很受伤前不久有消息称,华为10月21日奥地利维也纳活动的主角将是Mate50系列,但现在华为已经亲自澄清,活动的主角其实是nova系列。猜测Mate50的原因是屏幕分析机构专家DavidiPhone13被央视点名,撕下苹果的遮羞布,难怪价格越来越便宜自苹果公司正式发布新款iPhone13系列手机以来,国内消费者的热情居高不下,即便早前第一波将iPhone13拿到手的消费者在网上展示以及吐槽了iPhone13系列新机存在各种各样CBA4消息!小丁坐穿板凳,李楠挖到宝,山东扣篮绝杀,超新星伤退CBA首日热身赛全部结束,山东队凭借刘冠岑的抢断扣篮,最终以7473绝杀浙江队,主帅徐长锁首秀获得胜利,本场比赛,丁彦雨航出现在大名单中,不过可惜的是,一整场都坐在替补席,镜头多次全红婵被质疑!邓亚萍点评全红婵遭网友炮轰!被曲解还是博眼球?年仅14岁的全红婵,是当今最红的运动员。自东京奥运会一跳出名,全运会出色发挥,收获无数粉丝和各家媒体追捧。全红婵的教练曾表示过度的关注已经严重影响全红婵的生活和训练。目前,已经拒绝42岁吴尊晒全家福庆生,一家四口生日只差一天,11岁NieNie亭亭玉立10月10日,吴尊在个人社交平台上晒出一组九宫格的全家福合照,来为自己和老婆儿女庆生,他还发文称来祝我们一家四口生日快乐吧,一家人温馨出镜。据悉,10月10日是吴尊与女儿NeiNe因出演丑女无敌出名,失踪3年以为是退出娱乐圈了,其实是去世了因出演丑女无敌出名,失踪3年以为是退出娱乐圈了,其实是去世了,她是谁?凭借丑女无敌一角走红,之后却消失三年以后退出娱乐圈,其实却已经因病去世,她就是王洁曦。王洁曦也是一个可怜的姑娘舒淇靠魅力征服5个男人,屡受情伤,嫁当代韦小宝终获幸福1南方的风经不起北方的寒冷,迟到的深情比草都轻贱。这句话,用来形容影后舒淇,再适合不过了。她和她的爱情之间隔着一条鸿沟,世人的成见比洪水猛兽还要狠毒。把脱掉的衣服穿回来,舒淇用了几央视偶像,没一个正经要说什么叫融不进这吵闹的世界。央视新闻记者裴斐,一定深有体会。前段时间,央视中秋晚会探班直播。那天,应该是她主持生涯里耳朵最累的一天。这边自我介绍话音未落。那边撒贝宁朱广权尼格买提说说canopen模块怎样满足标准CANopenCia301协议本文接着来说说canopenio模块通讯报文格式应用的那些事,通讯报文格式1。启动命令,CANopenIO模块满足标准CANopenCia301协议,是标准的CANopen从站设备流量密码曝光脸书再陷危机豪根(中)在国会作证图GJ一名前脸书员工坐在镜头前,毫不留情地控诉老东家在明知会对社会造成负面影响的情况下,执意通过算法操纵内容呈现,试图以贩卖焦虑和煽动情绪来获取流量。脸书首席执现阶段最适合捡漏的四款旗舰手机,只因价格均开始走低当手机产品同质化严重之后,消费者在选择新机的时候也就变得很纠结,而且对于很多不熟悉手机的同学,经常会被各种错误的话术洗脑,从而觉得买个手机怎么这么难,我当时为什么会选择这款体验不好