Skip to content

Add GPU-accelerated 3D z-stack renderer#1096

Open
keejkrej wants to merge 6 commits into
SchmollerLab:mainfrom
keejkrej:feat/3d-z-render
Open

Add GPU-accelerated 3D z-stack renderer#1096
keejkrej wants to merge 6 commits into
SchmollerLab:mainfrom
keejkrej:feat/3d-z-render

Conversation

@keejkrej
Copy link
Copy Markdown
Contributor

@keejkrej keejkrej commented May 6, 2026

vispy 3d rendering of z-stacks, supports overlay channel and segmentation channel
don't merge yet, haven't thoroughly tested
feel free to checkout and test

Implements a standalone vispy-based 3D volume renderer with full Cell_ACDC
integration: multi-channel overlay, segmentation mask volumes, anisotropic
voxel scaling, plane/ISO/MIP depiction modes, smooth-ISO pre-filter,
percentile auto-contrast, opacity/contrast controls, keyboard shortcuts,
QSettings persistence, and screenshot export.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 6, 2026 19:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new GPU-accelerated 3D z-stack renderer (VisPy-based) and integrates it into the main GUI as a new z-projection option, alongside a large smoke-test suite intended to validate renderer behavior without requiring an active OpenGL window.

Changes:

  • Introduces cellacdc.renderer3d with a Qt window, controls, overlay volumes, voxel anisotropy scaling, and screenshot export.
  • Integrates the renderer into gui.py via a new z-projection dropdown entry and adapter-based wiring for feeding current volumes/overlays.
  • Adds renderer3d optional dependency group (VisPy + PyOpenGL) and a new tests/test_renderer3d.py test module.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.

File Description
tests/test_renderer3d.py Adds renderer3d smoke/API/tests, including vispy-compat checks and GUI integration expectations.
pyproject.toml Adds renderer3d optional dependencies and includes them in all.
cellacdc/renderer3d.py New VisPy/Qt 3D volume renderer window, controls, overlays, voxel scaling, settings persistence, screenshot export.
cellacdc/gui.py Adds “3D z-render” mode, launches/updates/hides renderer window, and supplies current z-stack + overlays + voxel sizes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/test_renderer3d.py
Comment thread tests/test_renderer3d.py

def test_interpolation_modes_valid_in_vispy():
"""Every INTERPOLATION_MODES id must be a valid vispy Volume interpolation."""
from cellacdc import renderer3d
Comment thread tests/test_renderer3d.py
Comment on lines +357 to +361
from cellacdc import renderer3d
import vispy
from qtpy import API_NAME
vispy.use(API_NAME)
from vispy.scene.visuals import Volume
Comment thread tests/test_renderer3d.py
Comment on lines +396 to +400
def test_depiction_plane_configs_valid_in_vispy():
"""_PLANE_CONFIGS normals must be unit vectors; vispy supports 'plane' mode."""
import vispy; from qtpy import API_NAME; vispy.use(API_NAME)
from vispy.scene.visuals import Volume
from cellacdc import renderer3d
Comment thread tests/test_renderer3d.py
Comment on lines +176 to +185
"""VolumeRenderer3DWindow must expose all expected public methods."""
from cellacdc.renderer3d import VolumeRenderer3DWindow
required = {
'update_volume', 'set_rendering_mode', 'set_colormap', 'set_clim',
'set_gamma', 'set_opacity', 'set_iso_threshold', 'set_attenuation',
'set_interpolation', 'set_step_size', 'set_smooth_iso',
'set_depiction', 'set_zplane_position', 'set_plane_thickness',
'set_voxel_scale', 'reset_view', 'save_screenshot',
'auto_contrast_percentile',
}
Comment thread tests/test_renderer3d.py
Comment on lines +591 to +595
s = QSettings(TEST_ORG, TEST_APP)
assert s.value('mode_idx', type=int) == 3
assert s.value('colormap', type=str) == 'viridis'
assert s.value('interp_idx', type=int) == 1
assert abs(s.value('clim_min', type=float) - 0.05) < 1e-6
Comment thread cellacdc/renderer3d.py
Comment on lines +93 to +97
COLORMAPS: list[str] = [
'grays', 'viridis', 'hot', 'coolwarm', 'blues', 'reds',
'greens', 'plasma', 'inferno', 'magma',
]

Comment thread cellacdc/renderer3d.py
except ImportError:
pass # scipy not available — skip smoothing silently
self._gpu_data_is_smoothed = smoothed
current_cmap = 'grays'
Comment thread cellacdc/renderer3d.py
s.setValue('clim_max', c._clim_max.value())
s.setValue('gamma', c._gamma_spin.value())
s.setValue('step_size', c._step_spin.value())
s.setValue('smooth_iso', c._smooth_iso_cb.isChecked())
Comment thread cellacdc/gui.py
Comment on lines 25346 to +25350
ol_img = img.mean(axis=0)
elif zProjHow == 'median z-proj.':
ol_img = np.median(img, axis=0)
else:
ol_img = img[z].copy()
@keejkrej
Copy link
Copy Markdown
Contributor Author

@codex review

@ElpadoCan ElpadoCan changed the title feat: add GPU-accelerated 3D z-stack renderer Add GPU-accelerated 3D z-stack renderer May 18, 2026
@ElpadoCan
Copy link
Copy Markdown
Collaborator

Hi @keejkrej,

Thank you for this contribution, it looks awesome!! 🚀

Before we merge, do you plan to look at the Copilot comments, or should I also have a look?

Also, the tests are failing because the vispy module is missing. Should Cell-ACDC handle the installation of vispy the first time the user tries this feature?

Thanks!

@keejkrej
Copy link
Copy Markdown
Contributor Author

Hi @ElpadoCan ,

it would be great if you can have a look at the copilot comments and make some changes. I think one has to make several important design choices to make the 3d renderer truly useful for segmentation (it's more than just model integrations).

@ElpadoCan
Copy link
Copy Markdown
Collaborator

3d renderer truly useful for segmentation

What do you mean by this? You mean displaying segmentation masks in the 3D renderer as well? Because editing segmentation masks in 3D sounds hard, I would not do it for now. What do you think?

@ElpadoCan
Copy link
Copy Markdown
Collaborator

Hi @keejkrej,

For now, I will remove the tests\test_renderer3d.py file from the automatic tests, because while it works locally, it fails on the GitHub VMs. This is likely because of GUI initialisation. I tried to fix it, but it now fails without any additional information.

@keejkrej
Copy link
Copy Markdown
Contributor Author

I mean whether to show 3d render in separate window or in side by side view in the gui. Do we need real time feedbacks for the segmentation? It is currently implemented as a post-validation of segmentation.

@ElpadoCan
Copy link
Copy Markdown
Collaborator

I actually like it in a separate window, what do you think @Teranis?

@ElpadoCan
Copy link
Copy Markdown
Collaborator

I mean whether to show 3d render in separate window or in side by side view in the gui. Do we need real time feedbacks for the segmentation? It is currently implemented as a post-validation of segmentation.

I don't think we need the ability to edit the segmentation masks in the 3d renderer. The only thing I would add is to display the segmentation masks overlaid with colours. Can we do this by displaying an image for the masks as well?

@ElpadoCan
Copy link
Copy Markdown
Collaborator

Cool feature that would be nice to have:

  • z-anisotropy adjustments with interpolation

This way, one can visualise volumes where the classic z-anisotropy is rendered as isotropic

@Teranis
Copy link
Copy Markdown
Member

Teranis commented May 19, 2026

Hi, this looks very cool! I like the idea that it's in a separate window since it's really just a visualisation. Along these lines, I would move the entry point to a dedicated button or menu option in the top ribbon, and if possible, make it so one could use the feature outside of the GUI as a utility.
Additionally I had the problem that there was an error (totally my fault, I forgot to install PyOpenGL), but the error only showed in the console, and nowhere on screen. I would suggest adding error handling similar to the workers and the main GUI!

@ElpadoCan
Copy link
Copy Markdown
Collaborator

Hi, this looks very cool! I like the idea that it's in a separate window since it's really just a visualisation. Along these lines, I would move the entry point to a dedicated button or menu option in the top ribbon, and if possible, make it so one could use the feature outside of the GUI as a utility.
Additionally I had the problem that there was an error (totally my fault, I forgot to install PyOpenGL), but the error only showed in the console, and nowhere on screen. I would suggest adding error handling similar to the workers and the main GUI!

Yes, I agree with everything. It would be cool if this was an easy to use python API as well.

Regarding UI, I'm working on some improvements.

For the missing packages, I will add automatic installation. I'm also planning to add a Cell ID selector to show only a specific cell (if segm is available of course).

Stay tuned 🚀

@ElpadoCan
Copy link
Copy Markdown
Collaborator

Yes, I agree with everything. It would be cool if this was an easy to use python API as well.

Note tha this is already possible like this

renderer = VolumeRenderer3DWindow()
renderer.update_volume(zstack_array)   # (Z, Y, X) numpy array
renderer.show()

We can add cellacdc._run._setup_app() before which checks if an application is already created or not. If not, it creates one and the API would be self sustained

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants