.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "_gallery/other/background_subtraction.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr__gallery_other_background_subtraction.py: A Method to Subtract Background from an Image ================================================ This example shows how to subtract a background from an image. The background is created via the mipmap levels of the image so that the background does not need to be computed per pixel during each render cycle. The mipmap level is sampled from to create the background. One can adjust the background level via the dropdown menu. Each level subtracts a subsampled background from the image with the subsampling increasing by a power of 2 with each level. Level 0 is the original image with no background subtraction. .. GENERATED FROM PYTHON SOURCE LINES 14-157 .. image-sg:: /_gallery/other/images/sphx_glr_background_subtraction_001.webp :alt: background subtraction :srcset: /_gallery/other/images/sphx_glr_background_subtraction_001.webp :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Imageio: 'hubble_deep_field.png' was not found on your computer; downloading it now. Try 1. Download from https://github.com/imageio/imageio-binaries/raw/master/images/hubble_deep_field.png (1.6 MB) Downloading: 8192/1668706 bytes (0.5%)1668706/1668706 bytes (100.0%) Done File saved as /home/docs/.imageio/images/hubble_deep_field.png. | .. code-block:: Python import imageio.v3 as iio import numpy as np from rendercanvas.auto import RenderCanvas, loop import pygfx as gfx from pygfx.renderers.wgpu import register_wgpu_render_function from pygfx.renderers.wgpu.shaders.imageshader import ImageShader from wgpu.utils.imgui import ImguiRenderer from imgui_bundle import imgui # Load image im = iio.imread("imageio:hubble_deep_field.png").astype(np.float32) X, Y = np.meshgrid( np.arange(im.shape[1]) - im.shape[1] / 2, np.arange(im.shape[0]) - im.shape[0] / 2 ) radius = np.sqrt(X**2 + Y**2) im *= 1 - radius[..., np.newaxis] / radius.max() im = im.astype(np.uint8) canvas_size = im.shape[0], im.shape[1] canvas = RenderCanvas(size=canvas_size, max_fps=999) renderer = gfx.renderers.WgpuRenderer(canvas, show_fps=True) scene = gfx.Scene() camera = gfx.OrthographicCamera(canvas_size[0], canvas_size[1]) camera.local.y = canvas_size[1] / 2 camera.local.scale_y = -1 camera.local.x = canvas_size[0] / 2 controller = gfx.PanZoomController(camera, register_events=renderer) image_texture = gfx.Texture(im, dim=2, generate_mipmaps=True) class BackGroundRemovedImageMaterial(gfx.ImageBasicMaterial): """ An image that has the background removed. """ uniform_type = dict( gfx.ImageBasicMaterial.uniform_type, background_level="u4", ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.background_level = 0 @property def background_level(self): return self.uniform_buffer.data["background_level"] @background_level.setter def background_level(self, value): self.uniform_buffer.data["background_level"] = int(value) self.uniform_buffer.update_range() @register_wgpu_render_function(gfx.Image, BackGroundRemovedImageMaterial) class BackGroundRemovedImageShader(ImageShader): def __init__(self, wobject): super().__init__(wobject) def get_code(self): code = super().get_code() code = code.replace( """ let value = sample_im(varyings.texcoord.xy, sizef); """, """ // Get the image value via bilinear interpolation var value: vec4 = textureSampleLevel(t_img, s_img, varyings.texcoord.xy, 0.); let background_level = f32(u_material.background_level); if background_level != 0.0 { // Get the background value via bilinear interpolation let background = textureSampleLevel(t_img, s_img, varyings.texcoord.xy, background_level); value = vec4( (value.rgb - background.rgb), value.a ); } """, ) return code image = gfx.Image( gfx.Geometry(grid=image_texture), BackGroundRemovedImageMaterial(clim=(0, 255), interpolation="linear"), ) scene.add(image) current_background_index = 0 current_image_index = 0 def draw_imgui(): global current_background_index global current_image_index global im, image_texture imgui.set_next_window_size((400, 0), imgui.Cond_.always) imgui.set_next_window_pos((0, 0), imgui.Cond_.always) is_expand, _ = imgui.begin("Controls", None) if is_expand: background_levels = ["0", "1", "2", "3", "4", "5", "6", "7", "8"] # Background level selection dropdown changed, current_background_index = imgui.combo( "Background Level", current_background_index, background_levels, len(background_levels), ) if changed: image.material.background_level = np.int32( background_levels[current_background_index] ) imgui.end() # Create GUI renderer gui_renderer = ImguiRenderer(renderer.device, canvas) def animate(): renderer.render(scene, camera) renderer.flush() gui_renderer.render() canvas.request_draw() gui_renderer.set_gui(draw_imgui) if __name__ == "__main__": canvas.request_draw(animate) loop.run() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.419 seconds) .. _sphx_glr_download__gallery_other_background_subtraction.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: background_subtraction.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: background_subtraction.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: background_subtraction.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_ .. only:: html Interactive example ------------------- Try this example in your browser using Pyodide. Might not work with all examples and all devices. Check the output and your browser's console for details. .. raw:: html