Multi-view Reconstruction
A 3D object can be reconstructed from multiple 2D views. ImageDisplacements is used to determine the parallax from one view to the next. The larger the parallax shift, the closer the object behind the corresponding pixel. With this depth information, you can extrude the vertices of an object mesh obtained through ImageMesh and TriangulateMesh. The result is displayed via texture mapping on the 3D mesh object.
Obtain an object mask of the central image.
mask = Erosion[Binarize[imgs[[2]], 0], 1];
Determine the parallax in the left and right images with respect to the center image.
parallaxL = First@ImageDisplacements[imgs[[{2, 1}]]];
parallaxR = First@ImageDisplacements[imgs[[{2, 3}]]];
Combine these displacements in a total parallax.
parallax = parallaxL - parallaxR;
In the given setting, the component of the parallax is roughly proportional to the depth of the respective pixel source.
depth = Blur@
Opening[ImageMultiply[ImageAdjust@Image[parallax[[All, All, 1]]],
mask], DiskMatrix[4]]
Construct a depth function.
depthFunction = ListInterpolation[Transpose@Reverse@ImageData[depth]];
Obtain an object mesh with a refinement that depends on the object's saliency.
resolution = ImageAdjust@ImageSaliencyFilter[imgs[[2]]];
resolutionFunction =
ListInterpolation[Transpose@Reverse@ImageData@resolution];
\[CapitalOmega] = TriangulateMesh[
ImageMesh[Erosion[mask, DiskMatrix[2]]],
MeshRefinementFunction ->
Function[{vertices, area},
area > 32 + 512 (1 - resolutionFunction @@ Mean[vertices])^6]
]
Extrude the object mesh with the depth function.
Graphics3D[
GraphicsComplex[
Apply[{##, depthFunction[##]} &,
MeshCoordinates[\[CapitalOmega]], {1}],
{EdgeForm[], MeshCells[\[CapitalOmega], 2]}
],
PlotRange -> Append[Thread[{0, ImageDimensions[mask]}], {0, 1}],
BoxRatios -> {1, 1, 2/3},
ViewPoint -> Top
]
Extract the object texture from the central image.
texture = SetAlphaChannel[imgs[[2]], mask]
Map the texture onto the 3D object.
Graphics3D[
{Texture[texture],
GraphicsComplex[
Apply[{##, depthFunction[##]} &,
MeshCoordinates[\[CapitalOmega]], {1}],
{EdgeForm[], MeshCells[\[CapitalOmega], 2]},
VertexTextureCoordinates ->
Map[#/ImageDimensions[texture] &, MeshCoordinates[\[CapitalOmega]]]
]
},
PlotRange -> Append[Thread[{0, ImageDimensions[mask]}], {0, 1}],
BoxRatios -> {1, 1, 2/3},
Lighting -> {{"Ambient", White}},
ViewPoint -> Top,
Boxed -> False
]