Skip to content

Upgrade WhipperSnapPy from 1.3 to 2.0, simplify and streamline integration#795

Open
ClePol wants to merge 4 commits intoDeep-MI:devfrom
ClePol:whippersnappy_bump
Open

Upgrade WhipperSnapPy from 1.3 to 2.0, simplify and streamline integration#795
ClePol wants to merge 4 commits intoDeep-MI:devfrom
ClePol:whippersnappy_bump

Conversation

@ClePol
Copy link
Member

@ClePol ClePol commented Feb 26, 2026

Overview

Upgrade to whippersnappy 2.0 with native EGL headless rendering, eliminating xvfb dependency and reducing Docker image size.

Changes

  • Direct data passing: Surface and overlay data passed in-memory instead of via disk I/O for better performance.
  • Validation checks: Added whippersnappy >= 2.0 version validation with clear error messages for users.
  • Removed xvfb & dependencies: Eliminated virtual framebuffer orchestration and X11-related libraries from Docker image.

Detailed Changes

  1. pyproject.toml — Version pin updated

    • whippersnappy>=1.3.1whippersnappy>=2.0
  2. requirements.mac.txt — Version pin updated

    • whippersnappy>=1.3.1whippersnappy>=2.0
  3. run_fastsurfer.sh — Removed xvfb orchestration

    • Removed entire maybe_xvfb block (lines 767–794)
    • Removed glfw/OpenGL/whippersnappy.core import test
    • Removed all associated warning messages
    • Simplified line 1184 by removing "${maybe_xvfb[@]}" prefix from CC module command invocation
    • Removed obsolete comment about xvfb-run wrapping
    • Note: Whippersnappy 2.0 renders headlessly via native EGL—no virtual framebuffer needed
  4. tools/Docker/Dockerfile — Slimmed runtime dependencies

    • Updated dependencies from: xvfb libglib2.0-0 libxkbcommon-x11-0 libgl1 libegl1 libfontconfig1 libdbus-1-3
    • To: libegl1 libgl1 libfontconfig1
    • Removed:
      • xvfb (virtual framebuffer, replaced by native EGL)
      • libglib2.0-0 (X11/GUI stack)
      • libxkbcommon-x11-0 (X11 keyboard)
      • libdbus-1-3 (D-Bus, X11-related)
    • Kept: libegl1 (EGL rendering), libgl1 (OpenGL), libfontconfig1 (font rendering for captions/colorbars)
  5. CorpusCallosum/shape/mesh.py — Updated import and API call

    • Removed import OpenGL.GL pre-check (whippersnappy 2.0 manages its own GL context)
    • Changed: from whippersnappy.core import snap1from whippersnappy import snap1 (new top-level import)
    • Removed the except Exception handler about xvfb (no longer relevant with EGL)
    • Updated snap1() call:
      • Positional first arg → mesh=
      • overlaypath=overlay= (new API parameter names)
  6. CorpusCallosum/cc_visualization.py — Updated version references

    • Help text and warning messages: whippersnappy>=1.3.1whippersnappy>=2.0
  7. CorpusCallosum/shape/postprocessing.py — Updated error messages

    • ImportError message: removed "glfw or OpenGL" (whippersnappy handles these internally)
    • Generic Exception message: replaced xvfb guidance with EGL/libegl1 guidance

…o 2.0:

1. pyproject.toml — Version pin updated
whippersnappy>=1.3.1 → whippersnappy>=2.0
2. requirements.mac.txt — Version pin updated
whippersnappy>=1.3.1 → whippersnappy>=2.0
3. run_fastsurfer.sh — Removed xvfb orchestration (lines 767–794 removed, line 1184 simplified)
Removed the entire maybe_xvfb block: xvfb-run detection, the glfw/OpenGL/whippersnappy.core import test, and all associated warning messages. Whippersnappy 2.0 renders headlessly via native EGL — no virtual framebuffer needed.
Removed "${maybe_xvfb[@]}" prefix from the CC module command invocation.
Removed the obsolete comment about xvfb-run wrapping.
4. tools/Docker/Dockerfile — Slimmed runtime dependencies
whippersnappy_opengl_deps="xvfb libglib2.0-0 libxkbcommon-x11-0 libgl1 libegl1 libfontconfig1 libdbus-1-3" → whippersnappy_egl_deps="libegl1 libgl1 libfontconfig1"
Removed: xvfb (virtual framebuffer, replaced by native EGL), libglib2.0-0 (X11/GUI stack), libxkbcommon-x11-0 (X11 keyboard), libdbus-1-3 (D-Bus, X11-related)
Kept: libegl1 (EGL rendering), libgl1 (OpenGL), libfontconfig1 (font rendering for captions/colorbars)
5. CorpusCallosum/shape/mesh.py — Updated import and API call
Removed import OpenGL.GL pre-check (whippersnappy 2.0 manages its own GL context)
Changed from whippersnappy.core import snap1 → from whippersnappy import snap1 (new top-level import)
Removed the except Exception handler about xvfb (no longer relevant with EGL)
Updated snap1() call: positional first arg → mesh=, overlaypath= → overlay= (new API parameter names)
6. CorpusCallosum/cc_visualization.py — Updated version references
Help text and warning messages: whippersnappy>=1.3.1 → whippersnappy>=2.0
7. CorpusCallosum/shape/postprocessing.py — Updated error messages
ImportError message: removed "glfw or OpenGL" (whippersnappy handles these internally)
Generic Exception message: replaced xvfb guidance with EGL/libegl1 guidance
◦
Detects if --thickness_image flag is present in cc_flags (which is set when the user uses --qc_snap)
◦
Checks whether the whippersnappy Python package is installed and >2.0
◦
Raises an error and gives instruction if this is not the case.
@ClePol
Copy link
Member Author

ClePol commented Feb 26, 2026

I just remembered that some other files might also need version bumps besides pyproject.toml like mac requirements. I think the other files are auto-generated?
It would be great if you could pick up from here, since I'm not so familiar with the install / dockerization of FastSurfer.

…face and overlay files.

Use direct passing of the surface and overlay data instead of writing the files to disc first.
Remove and simplify commands, arguments and the like that are a relict of older whippersnappy versions, now fully requiring whippersnappy 2.
@dkuegler dkuegler changed the title WhipperSnapPy2 upgrade Upgrade WhipperSnapPy from 1.3 to 2.0, simplify and streamline integration Feb 26, 2026
@dkuegler dkuegler marked this pull request as ready for review February 26, 2026 20:01
@dkuegler dkuegler requested a review from Copilot February 26, 2026 20:01
Copy link
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

This pull request upgrades the whippersnappy dependency from version 1.3 to 2.0, which introduces native EGL headless rendering capabilities. This eliminates the need for xvfb (virtual framebuffer) orchestration, simplifies the codebase, and reduces Docker image size by removing X11-related dependencies.

Changes:

  • Upgraded whippersnappy version requirement from >=1.3.1 to >=2.0 across all dependency files
  • Removed xvfb orchestration logic and replaced with whippersnappy version validation in run_fastsurfer.sh
  • Refactored mesh snapshot generation to use whippersnappy 2.0's in-memory API instead of disk-based I/O
  • Reduced Docker runtime dependencies by removing xvfb and X11-related libraries (libglib2.0-0, libxkbcommon-x11-0, libdbus-1-3)

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
pyproject.toml Updated whippersnappy version constraint in qc optional dependencies
requirements.mac.txt Updated whippersnappy version constraint for macOS builds
tools/Docker/Dockerfile Removed X11 dependencies and renamed variable to reflect EGL-based rendering
run_fastsurfer.sh Replaced xvfb orchestration with version validation logic, added error handling for version mismatches
CorpusCallosum/shape/mesh.py Updated API to use whippersnappy 2.0's direct data passing, added version check, updated imports
CorpusCallosum/shape/postprocessing.py Simplified mesh processing and updated error messages for EGL rendering
CorpusCallosum/cc_visualization.py Updated version references and adapted to new API signature

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

elif Path(template_dir / "mri/orig.mgz").exists() and Path(template_dir / "mri/transforms/cc_up.lta").exists():
image = nib.load(template_dir / "mri" / "orig.mgz")
lta_mat = read_lta(template_dir / "mri/transforms/cc_up.lta")["lta"]
image.affine = apply_affine(lta_mat, image.affine)
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The function apply_affine from nibabel.affines is used to transform points/vertices, not affine matrices. This line incorrectly applies apply_affine(lta_mat, image.affine) when it should be composing two affine matrices. The correct approach would be to matrix multiply: image.affine = lta_mat @ image.affine or use np.dot(lta_mat, image.affine). The current code will likely result in an error or incorrect transformation.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Should be addressed by matrix multiplication.

cc_mesh.snap_cc_picture(str(output_dir / "cc_mesh_snap.png"))
cc_mesh.snap_cc_picture(str(output_dir / "cc_mesh_snap.png"), ref_header=header)
logger.info(f"Writing 3D snapshot image to {output_dir / 'cc_mesh_snap.png'}")
except RuntimeError:
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The exception handler is catching RuntimeError, but the snap_cc_picture method in mesh.py (line 527-531, 535-539) raises ImportError exceptions, not RuntimeError. The exception type should be changed to ImportError or a broader Exception to properly catch the errors from snap_cc_picture.

Suggested change
except RuntimeError:
except ImportError:

Copilot uses AI. Check for mistakes.
- -8 degrees around z-axis
3. Adds a small translation for better centering
"""
from whippersnappy.gl.views import ViewType, get_view_matrix
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The import from whippersnappy.gl.views import ViewType, get_view_matrix is placed inside the method, but the method is called from snap_cc_picture which may fail before reaching this line if whippersnappy is not installed. Consider moving this import to be alongside the whippersnappy version check in snap_cc_picture or ensuring this import is protected by the same try-except block. Additionally, this new dependency on whippersnappy.gl.views should be validated to ensure it exists in whippersnappy 2.0.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

I had made ViewType top level import for convenience:
from whippersnappy import ViewType

Path to a FreeSurfer overlay file to use for the snapshot.
If None, the mesh is saved to a temporary file.
ref_image : Path, str, nibabelImage, optional
ref_header : Path, str, nibabelImage, optional
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The docstring parameter description says "ref_header : Path, str, nibabelImage, optional" but the type annotation on line 506 shows it accepts "nibabelHeader" not "nibabelImage". The docstring should be corrected to say "ref_header : Path, str, nibabelHeader, optional" to match the actual type annotation.

Suggested change
ref_header : Path, str, nibabelImage, optional
ref_header : Path, str, nibabelHeader, optional

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Well, actually this is the old type in the docstring. Most of the types of this string are currently not supported. We should just drop the types from the doc that are no longer supported.

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