-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Undistortion should not occur for already-undistorted images #2726
Conversation
…ccordingly fix rounding of downscaled image size
Wow, this is an interesting finding. |
] | ||
) | ||
|
||
if camera.camera_type.item() == CameraType.PERSPECTIVE.value and np.any(distortion_params): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change wouldn't be compatible with other features (mask, depth_image). I would suggest to check np.any(distortion_params)
and if False, return the original K and image without triggering cv2 functions. Something like below should work
if np.any(distortion_params):
newK, roi = cv2.getOptimalNewCameraMatrix(K, distortion_params, (image.shape[1], image.shape[0]), 0)
image = cv2.undistort(image, K, distortion_params, None, newK) # type: ignore
else:
newK = K
roi = 0, 0, image.width, image.height
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, I found the following lines are problematic, roi was calculated for undistorted images, not the original image/mask. Should be deleted maybe.
if "mask" in data:
data["mask"] = data["mask"][y : y + h, x : x + w]
if "depth_image" in data:
data["depth_image"] = data["depth_image"][y : y + h, x : x + w]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch. Fixed.
Per the other comment - I removed the lines for the mask, because indeed it occurs twice in the code. I left the depth as is.
Per the great comments from @jb-ye, we removed the problematic logic of image downscaling. Now, In addition, just to be clear, this PR leads to better results. Here are the results on the 'garden' sample, evaluated on the original evaluation set (i.e., without duplicated undistortion), comparing training with the original way to this PR.
|
what causes the blurriness exactly?
So it seems like the bug is actually in the ROI returned by cv2.getOptimalNewCameraMatrix
Outputs:
What is different between this code snippet and what happens in nerfstudio? |
I am getting a different
|
OK so maybe there are two problems. |
Ok, so the bug newK != K is present in OpenCV 4.6 and 4.7, bug is fixed in 4.8 (which is the version I used above). I suggest we:
|
Thanks for tracking that down! Bumping opencv to 4.9 sounds good to me, would this also fix #2683 or is that a separate problem? |
I think the ROI bug is not yet fixed even in the latest version, sadly. But as long as the input images are undistorted, the colmap loader should work as expected after this PR. |
#2683 is not the right fix. This is an upstream opencv issue (opencv/opencv#24831). |
Right. If the ROI issue with opencv is fixed, then #2683 will break.
|
…parameters of zero
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the catch!
This mostly concerns public datasets, like Mip-NeRF 360, which already comes undistorted.
The current logic undistorts even pinhole cameras. To avoid clashing with other logic in the code, we can just skip the undistortion if all distortion parameters are zero.
Unnecessary undistortion smoothes the images, and may incorrectly create the impression that image comparison metrics (PSNR, SSIM, LPIPS) are better. The PR in #2709 shows improvements in the implementation through multiple modifications, that are complementary to this change.
Here's a comparison of what it does to an image from the training set of 'garden',
![image](https://private-user-images.githubusercontent.com/19261832/294240323-6e154a40-a950-4d17-a0f9-b2224040e020.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxNzE0ODAsIm5iZiI6MTczOTE3MTE4MCwicGF0aCI6Ii8xOTI2MTgzMi8yOTQyNDAzMjMtNmUxNTRhNDAtYTk1MC00ZDE3LWEwZjktYjIyMjQwNDBlMDIwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjEwVDA3MDYyMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTVlZWU5NTIyM2JjMjllMDAwYmJiOGZhNmU4YmMzYmJhYWY2YWZhOTg2ODM4YmE0Zjc0YmVhOTdiY2FmNTUxYWUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.X-knwP7cZyMQjsAHUIfiDlwBO-nL6VcHgNBGsj3_F34)
On the garden dataset, without the undistortion the metrics are affected as follows (keep in mind that the change applies to the evaluation images as well, hence the metrics are lower),
While the metrics are lower after the change, they are aligned with other repositories (because the evaluation images are unnecessarily undistorted as well). Due to the added details, there are also more gaussians (5.1M gaussians without undistortion, compared to 3.8M with the unnecesary undistortion).
This change creates misalignment between how images are downscaled in nerfstudio compared to other repositories (and in Mip-NeRF 360). Hence, the rounding of the downscale factor in
cameras.py
. Without it, in 'garden', the original resolution of5187x3361
downscaled to 4, results in1296x840
. While in the supplied images in the data, the resolution is1297x840
. This occurs because5187/4=1296.75
. The change incameras.py
makes it necessary to apply the same logic to all downscaling mechanisms in the code. This shouldn't change much for most users (e.g., HD resolution).