gVirtualXray (gVXR) Bindings to simulate realist X-ray attenuation images in microseconds from triangle meshes.
Project description
gVirtualXray (gVXR): Virtual X-Ray Imaging Library on GPU
This project provides a programming framework for simulating X-ray images on the graphics processor unit (GPU) using OpenGL. In a nutshell, it computes the polychromatic version of the Beer-Lambert law (the mathematical model that relates the attenuation of X-ray photons to the properties of the material through which the photons are travelling) on the graphics card from polygon meshes. Mass attenuation coefficients are provided by xraylib. It supports ‘old’ OpenGL implementations as well as modern OpenGL core profile (OpenGL 3.2+). No deprecated function in OpenGL has been used. The library takes care of matrix transformations, matrix stacks, etc.
X-ray simulations created with gVirtualXRay have been used in various applications, including:
- real-time medical simulations for training purposes [1,2,3],
- micro-CT in material science application
- designing new clinical imaging techniques [6]
- teaching particle physics to undergraduate students [7]
- realistic data acquisition simulation in CT imaging with patient respiration [1,8,9].
Please check gVirtualXRay's website at http://gvirtualxray.sourceforge.net/ for more information.
Installation
pip install gvxr
You may also install Numpy, tifffile and Matplotlib to run the test below.
pip install numpy matplotlib tifffile
Usage
There are 6 main steps to simulate an X-ray image:
- Create a renderer (OpenGL context):
gvxr.createOpenGLContext()
- X-ray source:
- Position
- x: -40.0 cm,
- y: 0.0 cm,
- z: 0.0 cm,
gvxr.setSourcePosition(-40.0, 0.0, 0.0, "cm")
- Shape:
- cone beam:
gvxr.usePointSource()
, or - Parallel (e.g. synchrotron):
gvxr.useParallelBeam();
- cone beam:
- Position
- Spectrum:
- monochromatic (0.08 MeV, i.e. 80 keV),
- 1000 photons per ray,
gvxr.setMonoChromatic(0.08, "MeV", 1000)
- Detector:
- Position:
- x: 10.0 cm,
- y: 0.0 cm,
- z: 0.0 cm,
gvxr.setDetectorPosition(10.0, 0.0, 0.0, "cm")
- Orientation:
- 0, 0, -1
gvxr.setDetectorUpVector(0, 0, -1)
- Resolution:
- $640 \times 320$ pixels
gvxr.setDetectorNumberOfPixels(640, 320)
- Pixel spacing:
- 0.5, 0.5, mm
gvxr.setDetectorPixelSize(0.5, 0.5, "mm")
- Position:
- Sample:
- Welsh dragon in a STL file:
- ID: "Dragon",
- STL file: "input_data/welsh-dragon-small.stl",
- Unit: mm,
gvxr.loadMeshFile("Dragon", "input_data/welsh-dragon-small.stl", "mm")
- Material of the sample (ID = "Dragon"):
- For a chemical element such as iron, you can use the Z number or symbol:
gvxr.setElement("Dragon", 26)
, orgvxr.setElement("Dragon", "Fe")
- For a compound such as water, do not forget to specify the density:
gvxr.setCompound("Dragon", "H2O")
gvxr.setDensity("Dragon", 1.0, "g/cm3")
gvxr.setDensity("Dragon", 1.0, "g.cm-3")
- For a mixture such as Titanium-Aluminum-Vanadium alloy, do not forget to specify the density:
gvxr.setMixture("Dragon", "Ti90Al6V4")
gvxr.setMixture("Dragon", [22, 13, 23], [0.9, 0.06, 0.04])
gvxr.setMixture("Dragon", ["Ti", "Al", "V"], [0.9, 0.06, 0.04]) # Not yet implemented
gvxr.setDensity("Dragon", 4.43, "g/cm3")
gvxr.setDensity("Dragon", 4.43, "g.cm-3")
- For a chemical element such as iron, you can use the Z number or symbol:
- Welsh dragon in a STL file:
- Compute the corresponding X-ray image:
xray_image = gvxr.computeXRayImage()
You can find the Jupyter Notebook of the example below at: https://github.com/effepivi/gvxr-demos/blob/main/training-course/02-first_xray_simulation.ipynb.
#!/usr/bin/env python3
# Import packages
import os
import numpy as np # Who does not use Numpy?
has_mpl = True
try:
import matplotlib # To plot images
import matplotlib.pyplot as plt # Plotting
from matplotlib.colors import LogNorm # Look up table
from matplotlib.colors import PowerNorm # Look up table
font = {'family' : 'serif',
'size' : 15
}
matplotlib.rc('font', **font)
# Uncomment the line below to use LaTeX fonts
# matplotlib.rc('text', usetex=True)
except:
has_mpl = False
# from tifffile import imwrite # Write TIFF files
from gvxrPython3 import gvxr # Simulate X-ray images
# Create an OpenGL context
print("Create an OpenGL context")
gvxr.createOpenGLContext();
# Create a source
print("Set up the beam")
gvxr.setSourcePosition(-40.0, 0.0, 0.0, "cm");
gvxr.usePointSource();
# For a parallel source, use gvxr.useParallelBeam();
# Set its spectrum, here a monochromatic beam
# 1000 photons of 80 keV (i.e. 0.08 MeV) per ray
gvxr.setMonoChromatic(0.08, "MeV", 1000);
# The following is equivalent: gvxr.setMonoChromatic(80, "keV", 1000);
# Set up the detector
print("Set up the detector");
gvxr.setDetectorPosition(10.0, 0.0, 0.0, "cm");
gvxr.setDetectorUpVector(0, 0, -1);
gvxr.setDetectorNumberOfPixels(640, 320);
gvxr.setDetectorPixelSize(0.5, 0.5, "mm");
# Locate the sample STL file from the package directory
path = os.path.dirname(gvxr.__file__)
fname = path + "/welsh-dragon-small.stl"
# Load the sample data
if not os.path.exists(fname):
raise IOError(fname)
print("Load the mesh data from", fname);
gvxr.loadMeshFile("Dragon", fname, "mm")
print("Move ", "Dragon", " to the centre");
gvxr.moveToCentre("Dragon");
# Material properties
print("Set ", "Dragon", "'s material");
# Iron (Z number: 26, symbol: Fe)
gvxr.setElement("Dragon", 26)
gvxr.setElement("Dragon", "Fe")
# Liquid water
gvxr.setCompound("Dragon", "H2O")
gvxr.setDensity("Dragon", 1.0, "g/cm3")
gvxr.setDensity("Dragon", 1.0, "g.cm-3")
# Titanium Aluminum Vanadium Alloy
gvxr.setMixture("Dragon", "Ti90Al6V4")
gvxr.setMixture("Dragon", [22, 13, 23], [0.9, 0.06, 0.04])
# gvxr.setMixture("Dragon", ["Ti", "Al", "V"], [0.9, 0.06, 0.04]) # Not yet implemented
gvxr.setDensity("Dragon", 4.43, "g/cm3")
gvxr.setDensity("Dragon", 4.43, "g.cm-3")
# Compute an X-ray image
# We convert the array in a Numpy structure and store the data using single-precision floating-point numbers.
print("Compute an X-ray image");
x_ray_image = np.array(gvxr.computeXRayImage()).astype(np.single)
# Update the visualisation window
gvxr.displayScene()
# Create the output directory if needed
if not os.path.exists("output_data"):
os.mkdir("output_data")
# Save the X-ray image in a TIFF file and store the data using single-precision floating-point numbers.
gvxr.saveLastXRayImage('output_data/raw_x-ray_image-02.tif')
# The line below will also works
# imwrite('output_data/raw_x-ray_image-02.tif', x_ray_image)
# Save the L-buffer
gvxr.saveLastLBuffer('output_data/lbuffer-02.tif');
# Display the X-ray image
# using a linear colour scale
if has_mpl:
plt.figure(figsize=(10, 5))
plt.title("Image simulated using gVirtualXray\nusing a linear colour scale")
plt.imshow(x_ray_image, cmap="gray")
plt.colorbar(orientation='vertical');
plt.show()
# using a logarithmic colour scale
plt.figure(figsize=(10, 5))
plt.title("Image simulated using gVirtualXray\nusing a logarithmic colour scale")
plt.imshow(x_ray_image, cmap="gray", norm=LogNorm(vmin=x_ray_image.min(), vmax=x_ray_image.max()))
plt.colorbar(orientation='vertical');
plt.show()
# using a Power-law colour scale (gamma=0.5)
plt.figure(figsize=(10, 5))
plt.title("Image simulated using gVirtualXray\nusing a Power-law colour scale ($\gamma=0.5$)")
plt.imshow(x_ray_image, cmap="gray", norm=PowerNorm(gamma=1./2.))
plt.colorbar(orientation='vertical');
plt.show()
# Display the X-ray image and compare three different lookup tables
plt.figure(figsize=(17, 7.5))
plt.suptitle("Image simulated with gVirtualXray visualised", y=0.75)
plt.subplot(131)
plt.imshow(x_ray_image, cmap="gray")
plt.colorbar(orientation='horizontal')
plt.title("using a linear colour scale")
plt.subplot(132)
plt.imshow(x_ray_image, norm=LogNorm(), cmap="gray")
plt.colorbar(orientation='horizontal')
plt.title("using a logarithmic colour scale")
plt.subplot(133)
plt.imshow(x_ray_image, norm=PowerNorm(gamma=1./2.), cmap="gray")
plt.colorbar(orientation='horizontal');
plt.title("using a Power-law colour scale ($\gamma=0.5$)")
plt.tight_layout()
plt.savefig("output_data/projection-02.pdf", dpi=600);
# Change the sample's colour
# By default the object is white, which is not always pretty. Let's change it to purple.
red = 102 / 255
green = 51 / 255
blue = 153 / 255
gvxr.setColour("Dragon", red, green, blue, 1.0)
# This image can be used in a research paper to illustrate the simulation environment, in which case you may want to change the background colour to white with:
gvxr.setWindowBackGroundColour(1.0, 1.0, 1.0)
# Update the visualisation window
gvxr.displayScene()
# Take the screenshot and save it in a file
if has_mpl:
screenshot = gvxr.takeScreenshot()
plt.imsave("output_data/screenshot-02.png", np.array(screenshot))
# or display it using Matplotlib
plt.figure(figsize=(10, 10))
plt.imshow(screenshot)
plt.title("Screenshot of the X-ray simulation environment")
plt.axis('off');
plt.show()
# Interactive visualisation
# The user can rotate the 3D scene and zoom-in and -out in the visualisation window.
# - Keys are:
# - Q/Escape: to quit the event loop (does not close the window)
# - B: display/hide the X-ray beam
# - W: display the polygon meshes in solid or wireframe
# - N: display the X-ray image in negative or positive
# - H: display/hide the X-ray detector
# - Mouse interactions:
# - Zoom in/out: mouse wheel
# - Rotation: Right mouse button down + move cursor```
gvxr.renderLoop()
Build and test status of the trunk
gVirtualXRay may be built from source using CMake. It has been successfully tested on the following operating systems:
It should be possible to build it on other platforms, but this may not have been tested.
gVirtualXRay has been successfully tested on the following platforms:
- Laptops
- Windows and
- Apple
- Desktop PC:
- Windows and
- GNU/Linux
- Supercomputer:
with graphics cards from Nvidia, AMD and Intel.
It should be possible to run it on other platforms, but this has not been tested.
How to cite
If you use gVirtualXRay, cite both these papers:
- Vidal, F. P., Garnier, M., Freud, N., Létang, J. M., & John, N. W. Simulation of X-ray attenuation on the GPU. In Proceedings of Theory and Practice of Computer Graphics 2009, pages 25-32, Cardiff, UK, June 2009. Eurographics Association. DOI: 10.2312/LocalChapterEvents/TPCG/TPCG09/025-032
- Vidal, F. P., & Villard, P.-F. (2016). Development and validation of real-time simulation of X-ray imaging with respiratory motion. Computerized Medical Imaging and Graphics. DOI: 10.1016/j.compmedimag.2015.12.002
@article{Vidal2016ComputMedImagingGraph,
author = "Franck P. Vidal and Pierre-Frédéric Villard",
title = "Development and validation of real-time simulation of X-ray imaging
with respiratory motion ",
journal = "Computerized Medical Imaging and Graphics ",
year = "2016",
volume = "49",
pages = "1-15",
month = apr,
abstract = "Abstract We present a framework that combines evolutionary
optimisation, soft tissue modelling and ray tracing on \{GPU\} to
simultaneously compute the respiratory motion and X-ray imaging in
real-time. Our aim is to provide validated building blocks with high
fidelity to closely match both the human physiology and the physics of
X-rays. A CPU-based set of algorithms is presented to model organ
behaviours during respiration. Soft tissue deformation is computed with an
extension of the Chain Mail method. Rigid elements move according to
kinematic laws. A GPU-based surface rendering method is proposed to
compute the X-ray image using the Beer–Lambert law. It is provided as an
open-source library. A quantitative validation study is provided to
objectively assess the accuracy of both components: (i) the respiration
against anatomical data, and (ii) the X-ray against the Beer–Lambert law and
the results of Monte Carlo simulations. Our implementation can be used in
various applications, such as interactive medical virtual environment to
train percutaneous transhepatic cholangiography in interventional radiology,
2D/3D registration, computation of digitally reconstructed radiograph,
simulation of 4D sinograms to test tomography reconstruction tools.",
doi = "10.1016/j.compmedimag.2015.12.002",
pmid = {26773644},
issn = "0895-6111",
keywords = "X-ray simulation, Deterministic simulation (ray-tracing),
Digitally reconstructed radiograph, Respiration simulation,
Medical virtual environment, Imaging guidance,
Interventional radiology training",
publisher = {Elsevier},
}
@inproceedings{Vidal2009TPCG,
author = {F. P. Vidal and M. Garnier and N. Freud and J. M. L\'etang and N. W. John},
title = {Simulation of {X-ray} Attenuation on the {GPU}},
booktitle = {Proceedings of Theory and Practice of Computer Graphics 2009},
year = 2009,
pages = {25-32},
month = jun,
address = {Cardiff, UK},
annotation = {Jun~17--19, 2009},
note = {Winner of Ken Brodlie Prize for Best Paper},
doi = {10.2312/LocalChapterEvents/TPCG/TPCG09/025-032},
abstract = {In this paper, we propose to take advantage of computer graphics hardware
to achieve an accelerated simulation of X-ray transmission imaging,
and we compare results with a fast and robust software-only implementation.
The running times of the GPU and CPU implementations are compared
in different test cases. The results show that the GPU implementation
with full floating point precision is faster by a factor of about
60 to 65 than the CPU implementation, without any significant loss
of accuracy. The increase in performance achieved with GPU calculations
opens up new perspectives. Notably, it paves the way for physically-realistic
simulation of X-ray imaging in interactive time.},
keywords = {Physically based modeling, Raytracing, Physics},
publisher = {Eurographics Association},
}
Scientific and Industrial Collaboration
If you are interested in any form of collaboration (e.g. to develop your own application) on a research paper or grant proposal, drop the package maintainer an email.
Copyright
The source code of gVirtualXRay’s is available under the BSD 3-Clause License. For details on use and redistribution please refer to http://opensource.org/licenses/BSD-3-Clause.
References
- Sujar, A., Meuleman, A., Villard, P.-F., García, M., & Vidal, F. P. (2017). gVirtualXRay: Virtual X-Ray Imaging Library on GPU. In Computer Graphics and Visual Computing (CGVC) (pp. 61–68). DOI: 10.2312/cgvc.20171279
- Sujar, A., Kelly, G., García, M., & Vidal, F. P. (2019). Projectional Radiography Simulator: an Interactive Teaching Tool. In Computer Graphics and Visual Computing (CGVC). DOI: 10.2312/cgvc.20191267
- Zuo, Z., Qian, W. Y., Liao, X., & Heng, P. (2018). Position based catheterization and angiography simulation. In 2018 IEEE 6th International Conference on Serious Games and Applications for Health (SeGAH) (pp. 1–7). DOI: 10.1109/SeGAH.2018.8401369
- Wen, T., Mihail, R., Al-maliki, shatha, Letang, J., & Vidal, F. P. (2019). Registration of 3D Triangular Models to 2D X-ray Projections Using Black-box Optimisation and X-ray Simulation. In Computer Graphics and Visual Computing (CGVC). DOI: 10.2312/cgvc.20191265
- Vidal, F. P. (2018). gVirtualXRay -- Fast X-ray Simulation on GPU. In Workshop on Image-Based Finite Element Method for Industry 2018 (IBFEM-4i 2018). DOI: 10.5281/zenodo.1452506
- Albiol, F., Corbi, A., & Albiol, A. (n.d.). Densitometric Radiographic Imaging With Contour Sensors. IEEE Access, 7, 18902–18914. DOI: 10.1109/ACCESS.2019.2895925
- Corbi, A., Burgos, D., Vidal, F. P., Albiol, F., & Albiol, A. (2020). X-ray imaging virtual online laboratory for engineering undergraduates. European Journal of Physics, 41(1), 1--31. DOI: 10.1088/1361-6404/ab5011
- Vidal, F. P., & Villard, P.-F. (2016). Development and validation of real-time simulation of X-ray imaging with respiratory motion. Computerized Medical Imaging and Graphics. DOI: 10.1016/j.compmedimag.2015.12.002
- Simulated Motion Artefact in Computed Tomography. (2015). In Eurographics Workshop on Visual Computing for Biology and Medicine. DOI: 10.2312/vcbm.20151228.
© Copyright 2022, Dr Franck P. Vidal, School of Computer science and Electronic Engineering, Bangor University. All rights reserved
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 Distributions
Built Distributions
Hashes for gVXR-2.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1c1c300ba7332af3115ac915e6e1c013164133fd4464769f625d9d0a3113a8ea |
|
MD5 | 9f8e29ac1e3740aa5396986bfd8563b3 |
|
BLAKE2b-256 | 515e3605ac15c114edee14f51b5704bda11f8a9258d8bc7fa6133a24ade7d14c |
Hashes for gVXR-2.0.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ecc3a325be467eefce9b867fe3bcf1f8cbe96aad42e27c4d9d84aa5d4b678af6 |
|
MD5 | 8184c956e02648da13b00d5e39c335ba |
|
BLAKE2b-256 | 474fb5c999b5c365fc7186b77adad948f2e8a752dda9b88816cf16d90cc3c070 |
Hashes for gVXR-2.0.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e45ed42e57bdacd3609c5b1646dac2836fe4f34b907cdb1d1b139624fa4a03c5 |
|
MD5 | f830a6e36ea0b79e3eb084ddab412589 |
|
BLAKE2b-256 | 5b6fc7bf631eae34b7e8357902f9e19d2231c377080cb2fba8e04bc89d1ea1e2 |
Hashes for gVXR-2.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f4325615dc64d233799e70ebe4ae67b7c9b8239f6e445d31ff649f332e846b13 |
|
MD5 | 32ad17e982a2c13b0ecce246b0501af0 |
|
BLAKE2b-256 | 0a1a254a4f9f847a1eb45d62231635f04d46aeb4758c78523ef33ecab9db7e99 |
Hashes for gVXR-2.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f05d3a22fc0208d3c8735a53fb71e12e29c95755a678bb3cae10ed21ec68f116 |
|
MD5 | e0272a644276fa0f528f2fd0a15d3e44 |
|
BLAKE2b-256 | 7c5d3d0ccaf52fe6643e201b1b229e418659ea9e4559b160e540d2389e2c3639 |
Hashes for gVXR-2.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7e478584704c64f9e3769d2859b9e68fd09bd97578e04ba3721bf28ac845db1a |
|
MD5 | a1b8914fea7033a3fa9c40fc2ca5be13 |
|
BLAKE2b-256 | 076a9b0c7a799703576eb4ad292160c927d6787e0f565b5824c1ff1388a56a4a |
Hashes for gVXR-2.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 855e4bc8fa719b867026524da8ac320a95a034f6308b21b46c913b60bbf6dd3c |
|
MD5 | cbc68c4ab0042f207ddefda785d1012b |
|
BLAKE2b-256 | 65b38b1dfe3ffbc9237d9d7e50571a1902557ab09ec57c58d21a90af4a2f3371 |
Hashes for gVXR-2.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4630c7ce74093cdc86bb6ebdf9eb38327fdba66ff55860b5d8fd32a5359e9c1a |
|
MD5 | bb34ee9c5e3cfbcdcd083a7965574990 |
|
BLAKE2b-256 | 7d800adafce006c7529f0e90ebc7e0fc8bfe3fedbc194b9da5065d0962c3bbfa |
Hashes for gVXR-2.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 37239ed2bad398b5278fb653f4c6d861278192a06bd6178d28b66de9dc04e15b |
|
MD5 | f6f45c79a6ab16d2a88e523bb2a56344 |
|
BLAKE2b-256 | 2890c5c569015fe4bd6d13cfaf5b79f621919db8e14cf1958da458444121fe8b |