Open3D icon indicating copy to clipboard operation
Open3D copied to clipboard

Wrong background color using Open3DScene

Open frebro83 opened this issue 1 year ago • 8 comments

Checklist

Describe the issue Using Open3DScene set_background seems to result in slightly wrong color. Attempting to match the 1E1E1E color of visual studio code results in 0D0D0D, am I missing something?

Steps to reproduce the bug

import open3d as o3d

class ColorTest:
    def __init__(self):
        self.window = o3d.visualization.gui.Application.instance.create_window(
            "ColorTest", 640, 480)
        self.scene = o3d.visualization.gui.SceneWidget()
        self.scene.scene = o3d.visualization.rendering.Open3DScene(
            self.window.renderer)
        
        # Following line is supposed to set background color to 1E1E1E,
        # alpha is ignored.
        self.scene.scene.set_background([30/255, 30/255, 30/255, 1])
        
        # Show something on screen
        self.scene.scene.show_axes(True)

        # Setup camera towards origin
        bbox = o3d.geometry.AxisAlignedBoundingBox([-1, -1, -1],
                                                   [1, 1, 1])
        self.scene.setup_camera(60, bbox, [0, 0, 0])

        self.window.add_child(self.scene)

def main():
    o3d.visualization.gui.Application.instance.initialize()
    ColorTest()
    o3d.visualization.gui.Application.instance.run()

if __name__ == "__main__":
    main()

Error message None

Expected behavior FEngine (64 bits) created at 0000022BA0741050 (threading is enabled) FEngine resolved backend: OpenGL

Window appears with a background darker then expected (0D0D0D) with the axes shown.

Open3D, Python and System information

- Operating system: Windows 10
- Python version: Python 3.8
- Open3D version: 0.17.0
- System architecture: x86_64
- Is this a remote workstation?: no
- How did you install Open3D?: pip

Additional information No response

frebro83 avatar Mar 21 '23 22:03 frebro83

@errissa this gamma correction has been disturbing me for a while too... I usually have to manually photoshop the background before putting a screenshot in my paper. Is it possible to find a way to both use PBR and retain a white background?

theNded avatar Mar 21 '23 22:03 theNded

@frebro83 You're not doing anything wrong. By default the rendering pipeline does a number of post-processing steps which include color grading and tone mapping. So, the background color will almost never match exactly what you set it to be. The easy way to fix this if you need exact colors is to disable post processing in the _init_ method: self.scene.scene.view.set_post_processing(False). set_post_processing can be called anytime - you can keep it on when you don't care, but then disable it when you need perfectly accurate background color.

To make the effect more obvious I changed the background to white and captured these images.

Default rendering (with post processing):

with_post

Post processing disabled: no_post

@theNded The method described above should work for you but may or may not be easy to incorporate depending on how you're using the visualizer. Feel free to reach out on Discord or we can talk about it on Friday.

errissa avatar Mar 22 '23 01:03 errissa

So, I tested to set_post_processing as suggested and it worked for light backgrounds but I did not get any visual difference for dark backgrounds. In general I'd like to be able to turn off the gamma/color correction on background and/or skybox while keeping it on for any objects.

It is of course a bit backward and extra work, but I can always compensate for the gamma correction in the dark spectrum and in case I need to go close to white I could attempt to use the set_post_processing, depending on how much it will interrupt the object shading.

Thank you for the answer!

frebro83 avatar Mar 22 '23 18:03 frebro83

The color grading adapts to scene content so it is, generally speaking, less obvious for darker scenes. Unfortunately, the post processing effects are screen space effects so it's impossible to disable them for just the background.

errissa avatar Mar 23 '23 13:03 errissa

As the post_processing wasnt enough to disable this color grading for darker scenes, are there more settings that can be used to control this?

frebro83 avatar Mar 23 '23 13:03 frebro83

You can control the color grading explicitly. Instead of disabling the post processing you can do the following:

import open3d.visualization.rendering as rendering

...

cg_settings = rendering.ColorGrading(rendering.ColorGrading.Quality.ULTRA, rendering.ColorGrading.ToneMapping.LINEAR)
self.scene.scene.view.set_color_grading(cg_settings)

The first constructor parameter for ColorGrading takes a quality (LOW, MEDIUM, HIGH, ULTRA) and the second a tone mapping algorithm (LINEAR, ACES_LEGACY, ACES, FILMIC, UCHIMURA, REINHARD). The default is Uchimura. You would want LINEAR since it avoids non-linear transformations of the color. The ColorGrading class also has a temperature property which sets the white balance color temperature. There are many more options for configuring the color grading but it appears that other than the ones I just noted they are not exposed in the Python API.

errissa avatar Mar 23 '23 16:03 errissa

Ok, great. Thank you!

frebro83 avatar Mar 23 '23 22:03 frebro83

@errissa , @frebro83 I find that the results are still not very perfect with the proposed solutions. Below is an example for illustration.

import open3d as o3d
import open3d.visualization.rendering as rendering
from matplotlib import pyplot as plt

render = rendering.OffscreenRenderer(720, 720)

# setup geometry and camera
sphere = o3d.geometry.TriangleMesh.create_sphere(1.0)
sphere.compute_vertex_normals()
mat = rendering.MaterialRecord()
mat.base_color = [0.7, 0.7, 0.7, 1.0] 
mat.shader = 'defaultLit'
render.scene.add_geometry("sphere1", sphere, mat)
render.setup_camera(45, [0, 0, 0], [0, 0, 5.0], [0, 1, 0])

# setup background
render.scene.set_background([1.0, 1.0, 1.0, 1.0])
####################### Solution 1 #######################
cg_settings = rendering.ColorGrading(rendering.ColorGrading.Quality.ULTRA, rendering.ColorGrading.ToneMapping.LINEAR)
render.scene.view.set_color_grading(cg_settings)
####################### Solution 2 #######################
# render.scene.view.set_post_processing(False)

# render
cimg = render.render_to_image()
plt.imshow(cimg)
plt.show()

Environment

Python: 3.8.15 Open3D: 0.16.0 OS: Ubuntu 20.04

Problem with Solution 1

With solution 1, the background color is not [255, 255, 255]. Instead, it is about 253~254 (image below). I can get a [255, 255, 255] background by hacking: render.scene.set_background([10, 10, 10, 1.0]). But I just wonder whether it is possible to get 255 from render.scene.set_background([1.0, 1.0, 1.0, 1.0]) image

Problem with Solution 2

Solution 2 does give a [255, 255, 255] white background, however, the color is darker compared to solution 1. image Is it possible to get the similar visual effects (lighter colors) with solution 1, while keeping a [255, 255, 255] background?

yanghtr avatar Jan 24 '24 00:01 yanghtr