nerfstudio-project / nerfstudio

A collaboration friendly studio for NeRFs
https://docs.nerf.studio
Apache License 2.0
9.28k stars 1.25k forks source link

About camera pixel center offsets #2255

Open myaldiz opened 1 year ago

myaldiz commented 1 year ago

Hi there!

I am little confused about the offset of the pixel center conventions as one of the OpenCV commits and few other articles that focal points of image (c_x, c_y) are located at (width-1)/2 and (height-1)/2. That means top-left pixel center is located at (0,0) location.

Nerfstudio implementation adds 0.5 offset to the pixel coordinates in the code. Does that means if we calibrate camera through OpenCV convention, we have to post-process focal points to match added +0.5 offset? How does this affect the radial_and_tangential_undistort function?

Thank you!

maturk commented 1 year ago

Here the get_image_coords function is only used for ray generation. We treat an image as a grid with bounds (0,0) top-left and (width - 1 , height - 1) bottom-right (this is what the torch.arange does). However, these are grid indices (like meshgrid incides) and not actual coordinates of the pixel centers. So that is why +0.5 is added to grid indides to create coordinates from which we can generate rays from. Rays are generally generated from the middle point of a pixel (with maybe additional noise added in some computer graphics applications).

myaldiz commented 1 year ago

Thank you for the reply @maturk!

Generated rays are using +0.5 offset convention right? However, standard OpenCV camera calibration pipeline treats (0,0) as top-left pixel center for the camera intrinsics. You can see that in the commit I shared. That means generated rays (which we use the inverse of intrinsics matrix) will have a wrong offset.

I might have a mistake in my logic, please let me know.

taoran-git commented 5 days ago

I think it has something to do with rounding. Without the offset, the interval [n, n + 1) will be truncated to its left end point, introducing a small bias.

With the offset, the interval [n, n + 1) will be first mapped to [n + 0.5, n + 1.5). The first half would be truncated to n, the second half will be truncated to n + 1.

double b; int a = b + 0.5;

has the same affect as

double b; int a = std::round(b);