import{s as wt,n as vt,o as xt}from"../chunks/scheduler.7bc62968.js";import{S as bt,i as yt,g as l,s,r as I,m as d,H as V,A as _t,h as o,f as a,c as i,j as Ee,u as A,x as h,n as u,B as O,k as pt,y as m,a as n,v as E,d as G,t as B,w as U}from"../chunks/index.2f8492b0.js";import{H as X,E as $t}from"../chunks/EditOnGithub.2a9ce03a.js";function Tt(Ge){let f,K,Q,Y,c,ee,g,Be=`We’ve seen in the NeRF chapter how, given a large set of images, we can generate a three-dimensional representation of an object.
But sometimes we have only a handful of images or even just one.
Novel View Synthesis (NVS) is a collection of methods to generate views from new camera angles that are plausibly consistent with a set of images.
Once we have a large, consistent set of images we can use NeRF or a similar algorithm to construct a 3D representation.`,te,w,Ue=`Many methods have recently been developed for this task.
However, they can be divided into two general classes - those that generate an intermediate three-dimensional representation, which is rendered from a new viewing direction, and those that directly produce a new image.`,ae,v,Ve=`One key difficulty is that this task is almost always underdetermined.
For example, for an image of the back of a sign, there are many possible different things that could be on the front.
Similarly, there could be parts of the object that are occluded, with one part of an object in front of another.
If a model is trained to directly predict (regress) the unseen parts, with a loss penalizing errors in reconstructing held-out views, then by necessity the model will, when it is not clear what should be there, predict a blurry, grey colored region, as noted in <a href="https://jiataogu.me/nerfdiff/" rel="nofollow">NerfDiff</a>.
This has spurred interest in the use of generative, diffusion-based models, which are able to sample from multiple plausible possibilities for the unseen regions.`,ne,x,Oe=`Here we will briefly discuss two approaches, which are representative of the two classes.
<a href="https://alexyu.net/pixelnerf" rel="nofollow">PixelNeRF</a> directly predicts a NeRF for the scene from an input image.
<a href="https://zero123.cs.columbia.edu/" rel="nofollow">Zero123</a> adapts the Stable Diffusion latent diffusion model to directly generate new views without an intermediate 3D representation.`,se,b,ie,y,Xe=`PixelNeRF is a method that directly generates the parameters of a NeRF from one or more images.
In other words, it conditions the NeRF on the input images.
Unlike the original NeRF, which trains a MLP which takes spatial points to a density and color, PixelNeRF uses spatial features generated from the input images.`,le,_,Qe=`<img src="https://huggingface.co/datasets/hf-vision/course-assets/resolve/main/PixelNeRF_pipeline.png" alt="PixelNeRF diagram"/>
image from <a href="https://alexyu.net/pixelnerf" rel="nofollow">https://alexyu.net/pixelnerf</a>`,oe,r,We,Ie,Ae,re,mt='<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex"> x </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>',he,pe,ft='<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex"> \\pi </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span>',me,fe,dt='<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>W</mi><mo stretchy="false">(</mo><mi>π</mi><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex"> W(\\pi x) </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span>',de,ue,ut='<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex"> x </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>',ce,ge,ct='<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi></mrow><annotation encoding="application/x-tex"> d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span>',we,ve,gt='<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>W</mi><mo stretchy="false">(</mo><mi>π</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex"> W(\\pi(x)) </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">))</span></span></span></span>',xe,be,$,Je=`The original PixelNeRF model was trained on a relatively small set of renderings from the <a href="https://huggingface.co/datasets/ShapeNet/ShapeNetCore" rel="nofollow">ShapeNet</a> dataset.
The model is trained with either one or two input images, and attempts to predict a single novel view from a new camera angle.
The loss is the mean-squared error between the rendered and expected novel views.
A model was trained separately on each class of object (e.g. planes, benches, cars).`,ye,T,_e,M,Ke='<img src="https://huggingface.co/datasets/hf-vision/course-assets/resolve/main/PixelNeRF_input.png" alt="Input image of a chair"/> <img src="https://huggingface.co/datasets/hf-vision/course-assets/resolve/main/PixelNeRF_output.gif" alt="Rotating gif animation of rendered novel views"/>',$e,k,Ye='image from <a href="https://alexyu.net/pixelnerf" rel="nofollow">https://alexyu.net/pixelnerf</a>',Te,R,et='The PixelNeRF code can be found on <a href="https://github.com/sxyu/pixel-nerf" rel="nofollow">GitHub</a>',Me,L,ke,N,tt='In the <a href="https://arxiv.org/pdf/2307.05663.pdf" rel="nofollow">ObjaverseXL</a> paper, PixelNeRF was trained on a <em>much</em> larger dataset <a href="https://huggingface.co/datasets/allenai/objaverse-xl" rel="nofollow">allenai/objaverse-xl</a>.',Re,P,at=`See also - <a href="https://deepmind.google/discover/blog/neural-scene-representation-and-rendering/" rel="nofollow">Generative Query Networks</a>,
<a href="https://www.vincentsitzmann.com/srns/" rel="nofollow">Scene Representation Networks</a>,
<a href="https://arxiv.org/pdf/2311.04400.pdf" rel="nofollow">LRM</a>`,Le,H,Ne,C,nt=`Zero123 takes a different approach, being a diffusion model.
Rather than trying to generate a three-dimensional representation, it instead directly predicts the image from the new views.
The model takes a single input image, and the relative viewpoint transformation between the input and novel view direction.
It attempts to generate a plausible, 3D-consistent image from the novel view direction.`,Pe,F,st=`Zero123 is built upon the <a href="https://arxiv.org/abs/2112.10752" rel="nofollow">Stable Diffusion</a> architecture, and it was trained by fine-tuning existing weights.<br/>
However, it adds a few new twists.
The model actually starts with the weights from <a href="https://huggingface.co/spaces/lambdalabs/stable-diffusion-image-variations" rel="nofollow">Stable Diffusion Image Variations</a>, which uses the CLIP image embeddings (the final hidden state) of the input image to condition the diffusion U-Net, instead of a text prompt.
However, here these CLIP image embeddings are concatenated with the relative viewpoint transformation between the input and novel views.
(This viewpoint change is represented in terms of spherical polar coordinates.)`,He,S,it=`<img src="https://huggingface.co/datasets/hf-vision/course-assets/resolve/main/Zero123.png" alt="Zero123"/>
image from <a href="https://zero123.cs.columbia.edu" rel="nofollow">https://zero123.cs.columbia.edu</a>`,Ce,j,lt=`The rest of the architecture is the same as Stable Diffusion.
However, the latent representation of the input image is concatenated channel-wise with the noisy latents before being input into the denoising U-Net.`,Fe,z,ot='To explore this model further, see the <a href="https://huggingface.co/spaces/cvlab/zero123-live" rel="nofollow">Live Demo</a>',Se,q,je,Z,rt=`<a href="https://3d-diffusion.github.io/" rel="nofollow">3DiM</a> - X-UNet architecture, with cross-attention between input and noisy frames.
<a href="https://arxiv.org/pdf/2311.13617.pdf" rel="nofollow">Zero123-XL</a> - Trained on the larger objaverseXL dataset. See also <a href="https://huggingface.co/stabilityai/stable-zero123" rel="nofollow">Stable Zero 123</a>`,ze,D,ht='<a href="https://arxiv.org/abs/2310.15110" rel="nofollow">Zero123++</a> - Generates 6 new fixed views, at fixed relative positions to the input view, with reference attention between input and generated images',qe,W,Ze,J,De;return c=new X({props:{title:"Novel View Synthesis",local:"novel-view-synthesis",headingTag:"h1"}}),b=new X({props:{title:"PixelNeRF",local:"pixelnerf",headingTag:"h2"}}),T=new X({props:{title:"Results (from the PixelNeRF website)",local:"results-from-the-pixelnerf-website",headingTag:"h3"}}),L=new X({props:{title:"Related methods",local:"related-methods",headingTag:"h3"}}),H=new X({props:{title:"Zero123 (or Zero-1-to-3)",local:"zero123-or-zero-1-to-3",headingTag:"h2"}}),q=new X({props:{title:"Related methods",local:"related-methods",headingTag:"h3"}}),W=new $t({props:{source:"https://github.com/johko/computer-vision-course/blob/main/chapters/en/unit8/3d-vision/nvs.mdx"}}),{c(){f=l("meta"),K=s(),Q=l("p"),Y=s(),I(c.$$.fragment),ee=s(),g=l("p"),g.textContent=Be,te=s(),w=l("p"),w.textContent=Ue,ae=s(),v=l("p"),v.innerHTML=Ve,ne=s(),x=l("p"),x.innerHTML=Oe,se=s(),I(b.$$.fragment),ie=s(),y=l("p"),y.textContent=Xe,le=s(),_=l("p"),_.innerHTML=Qe,oe=s(),r=l("p"),We=d("The method first passes the input images through a convolutional neural network (ResNet34), bilinearly upsampling features from multiple layers to the same resolution as the input images."),Ie=l("br"),Ae=d(`
As in a standard NeRF, the new view is generated by volume rendering.
However, the NeRF itself has a slightly unusual structure.
At each query point`),re=new V(!1),he=d(" in the rendered volume, the corresponding point in the input image(s) is found (by projecting it using the input image camera transformation"),pe=new V(!1),me=d(` ).
The input image features at this point,`),fe=new V(!1),de=d(` are then found by bilinear interpolation.
Like in the original NeRF, the query point`),ue=new V(!1),ce=d(" is positionally encoded and concatentated with the viewing direction"),ge=new V(!1),we=d(`.
The NeRF network consists of a set of ResNet blocks; the input image features`),ve=new V(!1),xe=d(` pass through a linear layer, and are added to the features at the start of each of the first three residual blocks.
There are then two more residual blocks to further process these features, before an output layer reduces the number of channels to four (RGB+density).
When multiple input views are supplied, these are processed independently for the first three residual blocks, and then the features are averaged before the last two blocks.`),be=s(),$=l("p"),$.innerHTML=Je,ye=s(),I(T.$$.fragment),_e=s(),M=l("p"),M.innerHTML=Ke,$e=s(),k=l("p"),k.innerHTML=Ye,Te=s(),R=l("p"),R.innerHTML=et,Me=s(),I(L.$$.fragment),ke=s(),N=l("p"),N.innerHTML=tt,Re=s(),P=l("p"),P.innerHTML=at,Le=s(),I(H.$$.fragment),Ne=s(),C=l("p"),C.textContent=nt,Pe=s(),F=l("p"),F.innerHTML=st,He=s(),S=l("p"),S.innerHTML=it,Ce=s(),j=l("p"),j.textContent=lt,Fe=s(),z=l("p"),z.innerHTML=ot,Se=s(),I(q.$$.fragment),je=s(),Z=l("p"),Z.innerHTML=rt,ze=s(),D=l("p"),D.innerHTML=ht,qe=s(),I(W.$$.fragment),Ze=s(),J=l("p"),this.h()},l(e){const t=_t("svelte-u9bgzb",document.head);f=o(t,"META",{name:!0,content:!0}),t.forEach(a),K=i(e),Q=o(e,"P",{}),Ee(Q).forEach(a),Y=i(e),A(c.$$.fragment,e),ee=i(e),g=o(e,"P",{"data-svelte-h":!0}),h(g)!=="svelte-md009s"&&(g.textContent=Be),te=i(e),w=o(e,"P",{"data-svelte-h":!0}),h(w)!=="svelte-ip51yg"&&(w.textContent=Ue),ae=i(e),v=o(e,"P",{"data-svelte-h":!0}),h(v)!=="svelte-1qxehg6"&&(v.innerHTML=Ve),ne=i(e),x=o(e,"P",{"data-svelte-h":!0}),h(x)!=="svelte-zc8dx0"&&(x.innerHTML=Oe),se=i(e),A(b.$$.fragment,e),ie=i(e),y=o(e,"P",{"data-svelte-h":!0}),h(y)!=="svelte-ujrcl0"&&(y.textContent=Xe),le=i(e),_=o(e,"P",{"data-svelte-h":!0}),h(_)!=="svelte-1a5qqgg"&&(_.innerHTML=Qe),oe=i(e),r=o(e,"P",{});var p=Ee(r);We=u(p,"The method first passes the input images through a convolutional neural network (ResNet34), bilinearly upsampling features from multiple layers to the same resolution as the input images."),Ie=o(p,"BR",{}),Ae=u(p,`
As in a standard NeRF, the new view is generated by volume rendering.
However, the NeRF itself has a slightly unusual structure.
At each query point`),re=O(p,!1),he=u(p," in the rendered volume, the corresponding point in the input image(s) is found (by projecting it using the input image camera transformation"),pe=O(p,!1),me=u(p,` ).
The input image features at this point,`),fe=O(p,!1),de=u(p,` are then found by bilinear interpolation.
Like in the original NeRF, the query point`),ue=O(p,!1),ce=u(p," is positionally encoded and concatentated with the viewing direction"),ge=O(p,!1),we=u(p,`.
The NeRF network consists of a set of ResNet blocks; the input image features`),ve=O(p,!1),xe=u(p,` pass through a linear layer, and are added to the features at the start of each of the first three residual blocks.
There are then two more residual blocks to further process these features, before an output layer reduces the number of channels to four (RGB+density).
When multiple input views are supplied, these are processed independently for the first three residual blocks, and then the features are averaged before the last two blocks.`),p.forEach(a),be=i(e),$=o(e,"P",{"data-svelte-h":!0}),h($)!=="svelte-18yx0n5"&&($.innerHTML=Je),ye=i(e),A(T.$$.fragment,e),_e=i(e),M=o(e,"P",{"data-svelte-h":!0}),h(M)!=="svelte-kuwwii"&&(M.innerHTML=Ke),$e=i(e),k=o(e,"P",{"data-svelte-h":!0}),h(k)!=="svelte-1fd4odk"&&(k.innerHTML=Ye),Te=i(e),R=o(e,"P",{"data-svelte-h":!0}),h(R)!=="svelte-zil5op"&&(R.innerHTML=et),Me=i(e),A(L.$$.fragment,e),ke=i(e),N=o(e,"P",{"data-svelte-h":!0}),h(N)!=="svelte-jcdds8"&&(N.innerHTML=tt),Re=i(e),P=o(e,"P",{"data-svelte-h":!0}),h(P)!=="svelte-ien78q"&&(P.innerHTML=at),Le=i(e),A(H.$$.fragment,e),Ne=i(e),C=o(e,"P",{"data-svelte-h":!0}),h(C)!=="svelte-177283l"&&(C.textContent=nt),Pe=i(e),F=o(e,"P",{"data-svelte-h":!0}),h(F)!=="svelte-2ht5cx"&&(F.innerHTML=st),He=i(e),S=o(e,"P",{"data-svelte-h":!0}),h(S)!=="svelte-1t7mcg"&&(S.innerHTML=it),Ce=i(e),j=o(e,"P",{"data-svelte-h":!0}),h(j)!=="svelte-5qhqp7"&&(j.textContent=lt),Fe=i(e),z=o(e,"P",{"data-svelte-h":!0}),h(z)!=="svelte-ggnn2t"&&(z.innerHTML=ot),Se=i(e),A(q.$$.fragment,e),je=i(e),Z=o(e,"P",{"data-svelte-h":!0}),h(Z)!=="svelte-117i4gt"&&(Z.innerHTML=rt),ze=i(e),D=o(e,"P",{"data-svelte-h":!0}),h(D)!=="svelte-1yfjeya"&&(D.innerHTML=ht),qe=i(e),A(W.$$.fragment,e),Ze=i(e),J=o(e,"P",{}),Ee(J).forEach(a),this.h()},h(){pt(f,"name","hf:doc:metadata"),pt(f,"content",Mt),re.a=he,pe.a=me,fe.a=de,ue.a=ce,ge.a=we,ve.a=xe},m(e,t){m(document.head,f),n(e,K,t),n(e,Q,t),n(e,Y,t),E(c,e,t),n(e,ee,t),n(e,g,t),n(e,te,t),n(e,w,t),n(e,ae,t),n(e,v,t),n(e,ne,t),n(e,x,t),n(e,se,t),E(b,e,t),n(e,ie,t),n(e,y,t),n(e,le,t),n(e,_,t),n(e,oe,t),n(e,r,t),m(r,We),m(r,Ie),m(r,Ae),re.m(mt,r),m(r,he),pe.m(ft,r),m(r,me),fe.m(dt,r),m(r,de),ue.m(ut,r),m(r,ce),ge.m(ct,r),m(r,we),ve.m(gt,r),m(r,xe),n(e,be,t),n(e,$,t),n(e,ye,t),E(T,e,t),n(e,_e,t),n(e,M,t),n(e,$e,t),n(e,k,t),n(e,Te,t),n(e,R,t),n(e,Me,t),E(L,e,t),n(e,ke,t),n(e,N,t),n(e,Re,t),n(e,P,t),n(e,Le,t),E(H,e,t),n(e,Ne,t),n(e,C,t),n(e,Pe,t),n(e,F,t),n(e,He,t),n(e,S,t),n(e,Ce,t),n(e,j,t),n(e,Fe,t),n(e,z,t),n(e,Se,t),E(q,e,t),n(e,je,t),n(e,Z,t),n(e,ze,t),n(e,D,t),n(e,qe,t),E(W,e,t),n(e,Ze,t),n(e,J,t),De=!0},p:vt,i(e){De||(G(c.$$.fragment,e),G(b.$$.fragment,e),G(T.$$.fragment,e),G(L.$$.fragment,e),G(H.$$.fragment,e),G(q.$$.fragment,e),G(W.$$.fragment,e),De=!0)},o(e){B(c.$$.fragment,e),B(b.$$.fragment,e),B(T.$$.fragment,e),B(L.$$.fragment,e),B(H.$$.fragment,e),B(q.$$.fragment,e),B(W.$$.fragment,e),De=!1},d(e){e&&(a(K),a(Q),a(Y),a(ee),a(g),a(te),a(w),a(ae),a(v),a(ne),a(x),a(se),a(ie),a(y),a(le),a(_),a(oe),a(r),a(be),a($),a(ye),a(_e),a(M),a($e),a(k),a(Te),a(R),a(Me),a(ke),a(N),a(Re),a(P),a(Le),a(Ne),a(C),a(Pe),a(F),a(He),a(S),a(Ce),a(j),a(Fe),a(z),a(Se),a(je),a(Z),a(ze),a(D),a(qe),a(Ze),a(J)),a(f),U(c,e),U(b,e),U(T,e),U(L,e),U(H,e),U(q,e),U(W,e)}}}const Mt='{"title":"Novel View Synthesis","local":"novel-view-synthesis","sections":[{"title":"PixelNeRF","local":"pixelnerf","sections":[{"title":"Results (from the PixelNeRF website)","local":"results-from-the-pixelnerf-website","sections":[],"depth":3},{"title":"Related methods","local":"related-methods","sections":[],"depth":3}],"depth":2},{"title":"Zero123 (or Zero-1-to-3)","local":"zero123-or-zero-1-to-3","sections":[{"title":"Related methods","local":"related-methods","sections":[],"depth":3}],"depth":2}],"depth":1}';function kt(Ge){return xt(()=>{new URLSearchParams(window.location.search).get("fw")}),[]}class Pt extends bt{constructor(f){super(),yt(this,f,kt,Tt,wt,{})}}export{Pt as component};
