v9.1.1
Menu

Surface Integration from Normals

mediumPROPhotometric StereoCVCV: 3D Reconstruction

Implement a method to integrate surface normals and recover a depth map, a crucial step in 3D Reconstruction using Photometric Stereo. This process involves calculating the surface gradient from given normals.

The surface gradient is a fundamental concept in Computer Vision, representing the rate of change of the surface depth in the x and y directions. Given the surface normals nxn_x, nyn_y, nzn_z, the surface gradient can be calculated as p=−nx/nzp = -n_x/n_z and q=−ny/nzq = -n_y/n_z, which are essential for integrating the surface.

To integrate the surface, follow these steps:

  1. Calculate the surface gradient pp and qq from the given normals.
  2. Integrate the gradient to obtain the depth ZZ: accumulate pp along each row (left to right) and qq down each column (top to bottom), and add the two.
  3. Shift the result so the mean depth is zero (absolute depth cannot be recovered from normals).
p=−nx/nz,q=−ny/nzp = -n_x/n_z, \quad q = -n_y/n_z Zij=∑k=0jpik+∑k=0iqkj,Z←Z−ZˉZ_{ij} = \sum_{k=0}^{j} p_{ik} + \sum_{k=0}^{i} q_{kj}, \qquad Z \leftarrow Z - \bar{Z}

Return a depth map of shape (height, width).

This technique is widely used in 3D scanning and object recognition applications.

Example

Input
Normal map
Output
Depth map
Reasoning
  • Input: a 2×3×32 \times 3 \times 3 normal map where every pixel holds the same unit normal (nx,ny,nz)=(−0.4472,0,0.8944)(n_x, n_y, n_z) = (-0.4472, 0, 0.8944), i.e. a plane tilted only in xx.
  • Gradient: p=−(−0.4472)/0.8944=0.5p = -(-0.4472)/0.8944 = 0.5 and q=−0/0.8944=0q = -0/0.8944 = 0 at every pixel, so depth rises by 0.50.5 per step to the right and does not change going down.
  • Integrate: accumulating pp along each row gives 0.5,1.0,1.50.5, 1.0, 1.5; accumulating qq down each column adds 00, so both rows are [0.5,1.0,1.5][0.5, 1.0, 1.5].
  • Centre: the mean depth is Zˉ=1.0\bar{Z} = 1.0, and subtracting it gives [−0.500.5−0.500.5]\begin{bmatrix} -0.5 & 0 & 0.5 \\ -0.5 & 0 & 0.5 \end{bmatrix}, one depth per pixel (shape 2×32 \times 3).
  • Notice that normals only fix slopes, never absolute height, which is why the result is centred on zero. A flat surface (all normals (0,0,1)(0,0,1), as in the 10×1010 \times 10 test) gives p=q=0p = q = 0 and an all-zero depth map.

Constraints

  • Input normals: 2D numpy array of shape (height, width, 3) with dtype float32, representing the surface normals nxn_x, nyn_y, nzn_z
  • Valid ranges: nzn_z values are non-zero, and all normal values are normalized to have a length of 1
  • Output depth map: 2D numpy array of shape (height, width) with dtype float32, representing the recovered depth ZZ with precision up to 6 decimal places
  • Special conditions: The input normals are assumed to be noise-free and the surface is assumed to be Lambertian and convex
  • Boundary conditions: The depth values at the boundary of the image are assumed to be zero, and the Poisson equation solver should handle the boundary conditions accordingly

Learn this in

More from CV: 3D Reconstruction

PRO

Editor locked

The code editor is locked for Pro problems. It is only available for free problems. Please upgrade to gain access to the code editor for all problems.

solution.py

Test results

Sign in to run your code against the test cases.