Pythonic interface for interacting with Osirix through a gRPC protocol
Project description
pyOsiriX
pyOsiriX provides a pythonic interface to the OsiriXgrpc plugin for the OsiriX medical image viewing platform. Our vision is to accelerate the development of robust research image processing tools for the medical community, including straight-forward deployment of AI algorithms.
Example functionality includes:
- Interrogating metadata of studies/series/imaging included within the OsiriX database.
- Accessing and adjusting pixel values within a 2D OsiriX viewer.
- Adjusting visualization settings of 3D volume rendering windows.
- Obtaining and creating regions of interest (ROIs) within image viewing windows.
Installation
pip install pyosirix
Requirements
Contributions
If you would like to contribute to pyOsiriX, please have a look at our contributing page. We are always eager to hear your ideas and improve pyOsiriX. Examples include:
- Publishing example scripts of pyOsiriX in use. For example, something small that helps your day-to-day workflows.
- Editing documentation or suggesting changes.
- Reporting any bugs you find by raising an issue.
- Testing new version of pyOsiriX (and OsiriXgrpc!) prior to release.
- Contributing to or suggesting changes to the whole project, including requests for more OsiriX function exposure.
Please contact us at osirixgrpc@gmail.com to find out more.
Examples of use
Note: These are for exemplary use only and just touch on what is possible with OsiriXgrpc. Over time we will compile a list of more complete examples as found in the documentation.
Accessing the 2D viewer
If 2D OsiriX viewers are open, it is possible to obtain its instance by simply running:
import osirix
displayed_viewers = osirix.displayed_2d_viewers() # Returns a list of all open viewers
frontmost_viewer = osirix.frontmost_viewer() # Returns the viewer that is currently active (red frame)
Accessing image data
It is straightforward to obtain image data within the 2D viewer and manipulate it. The following doubles the pixel values of the currently displayed image.
import osirix
frontmost_viewer = osirix.frontmost_viewer()
pixels = frontmost_viewer.cur_dcm().image # Obtain pixel data (as 2D NumPy array) from currently displayed image slice.
new_pixels = pixels * 2 # Manipulate the array
frontmost_viewer.cur_dcm().image = new_pixels # Update the image data for the currently shown image slice.
frontmost_viewer.needs_display_update() # Tell OsiriX to redraw itself
Accessing (all) image data
Images in the viewer are stored in arrays, one array per frame, each array having the same length as the number of displayed slices. The following does the same as the example above, but applies to all images in the viewer.
import osirix
frontmost_viewer = osirix.frontmost_viewer()
pix_list = frontmost_viewer.pix_list(0) # Obtain an array of DCMPix objects for the first (zeroth) frame.
for pix in pix_list: # Loop through all DCMPix
pixels = pix.image
new_pixels = pixels * 2 # Manipulate the array
pix.image = new_pixels
frontmost_viewer.needs_display_update() # Tell OsiriX to redraw itself
Accessing ROIs
Similarly to images, ROIs can be obtained as an array for each requested frame in the 2D OsiriX viewer. Each element of the array is another array, containing however many ROIs are on that slice (some may be empty). This will produce a list of unique ROI names in the viewer.
import osirix
frontmost_viewer = osirix.frontmost_viewer()
roi_list = frontmost_viewer.roi_list(0) # ROI list for the first (zeroth) frame.
unique_names = [] # Empty storage
for roi_slice in roi_list:
for roi in roi_slice: # There may be more than one ROI in a slice!
if roi.name not in unique_names: # You could also use numpy.unique...
unique_names.append(roi.name)
if len(unique_names) == 0:
print("No ROIs found in the viewer!")
else:
print(f"Unique names are: {unique_names}")
Accessing ROIs by name
If you know the name of the ROI it is easy to avoid looping through
import osirix
frontmost_viewer = osirix.frontmost_viewer()
roi_name = "my_perfect_roi"
rois = frontmost_viewer.rois_with_name(roi_name)
print(f"Number of ROIs with name {roi_name}: {len(rois)}")
Converting an ROI to a mask
Another useful thing to do is obtain a mask (a 2D array of boolean values) representing the region of the ROI. To do this you need a DCMPix instance to compute it from. Luckily, this is easy to obtain!
import osirix
import numpy as np
frontmost_viewer = osirix.frontmost_viewer()
roi_name = "my_perfect_roi"
rois = frontmost_viewer.rois_with_name(roi_name)
if len(rois) == 0:
raise ValueError(f"Could not find any ROIs with the name {roi_name}")
voxels = [] # Storage
for roi in rois:
pix = roi.pix # The DCMPix on which the ROI was drawn
mask = pix.get_map_from_roi(roi) # The mask we wanted.
voxels = np.r_[pix.image[mask], voxels] # Append the voxel values
mean = np.mean(voxels) # Let's get some statistics
std = np.std(voxels, ddof=1)
print(f"ROIs with name {roi_name} have mean {mean:.2f} and std-dev {std: .2f}")
Accessing Dicom files in the OsiriX database
It is possible to get access to the selected series and studies in the OsiriX database. This example sorts the DicomImages in the first selected DicomSeries by slice location and then opens them in a new 2D viewer.
import osirix
import numpy as np
browser_controller = osirix.current_browser() #The main window (database) of OsiriX
studies, series = browser_controller.database_selection() # User selection as lists of DicomStudy/DicomSeries
if len(series) == 0:
raise ValueError("No series have been selected")
dicom_images = np.array(series[0].images) # An array of DicomImage instances
sorted_idx = np.argsort([image.slice_location for image in dicom_images]) # Sort the images by slice location
dicom_images = dicom_images[sorted_idx]
viewer_controller = browser_controller.open_viewer_2d(dicom_images) # Open up and view
Accessing the VRController
Once a user has opened a VRController (or done so programmatically via pyOsiriX!), it is possible to access it as per the 2D viewer. This example shows this and also how to make the contained ROIVolumes display themselves.
import osirix
frontmost_viewer = osirix.frontmost_viewer()
vr_controllers = frontmost_viewer.vr_controllers() # Get a list of currently open ones.
if len(vr_controllers) == 0:
print("No open VR Controller. Creating one.")
vr_controller = frontmost_viewer.open_vr_viewer(mode="MIP") # Only other alternative is "VR"
else:
vr_controller = vr_controllers[0]
roi_volumes = vr_controller.roi_volumes()
if len(roi_volumes) == 0:
print("No valid ROI volumes available") # Note that ROIs defined on a single slice do not count!
for roi_volume in roi_volumes:
print(f"Displaying ROI volume with name {roi_volume.name} and modifying is attributes")
roi_volume.visible = True
roi_volume.color = (1., 0., 1.) # Purple color in unit RGB space
roi_volume.opacity = 0.5
roi_volume.texture = False # Generally looks better to us
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pyosirix-0.2.1b5.tar.gz
.
File metadata
- Download URL: pyosirix-0.2.1b5.tar.gz
- Upload date:
- Size: 29.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 03629b76556fda03632cc5fddc36775d8091dac895edce32d80abf7f6fcd6497 |
|
MD5 | 4a1e389deec364bbfb78842caba103d3 |
|
BLAKE2b-256 | e543abdec2f95769905531b88242f91eb70ff317700dc1f26aef9ffc93c8d49c |
File details
Details for the file pyosirix-0.2.1b5-py3-none-any.whl
.
File metadata
- Download URL: pyosirix-0.2.1b5-py3-none-any.whl
- Upload date:
- Size: 30.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b986995874c0b1f284a4d8bcbe3244c42943f0a3a83bfead4540a2a110df0568 |
|
MD5 | 273de2bcfdd0e9ddd8cfbf8c389071b0 |
|
BLAKE2b-256 | 97be5bddebd3013507fcd52e7703636ddb5929459aea13fdba4664ed4b3238dd |