Menu

Tree [bea997] master /
 History

HTTPS access


File Date Author Commit
 SimpleGVXR 5 days ago effepivi effepivi [651895] Start planning the addition of the inherent fil...
 SimpleGVXR-examples 2019-05-07 Franck Vidal Franck Vidal [2ffd07] Add license file.
 Wrappers 2026-02-25 effepivi effepivi [d8de39] Remove the use of Numpy. It's not needed.
 cmake 2026-02-11 effepivi effepivi [fc0ae2] Fix dependency issues when Ninja is used as a C...
 doc 7 days ago Franck Vidal Franck Vidal [4e3a05] Add content.
 docker 2026-01-05 effepivi effepivi [7bf5ac] Add an example using a docker container for Jet...
 gvxr 2 days ago effepivi effepivi [bea997] Fix typo in ifdef.
 gvxrGUI 2024-07-24 effepivi effepivi [dbb0b9] Change into .
 logo-pack 2025-08-03 Franck Vidal Franck Vidal [7395d5] Add file.
 pip 2026-02-16 effepivi effepivi [b04b1c] Add missing "fi" to end and if statement.
 screenshots 2020-01-16 Franck Vidal Franck Vidal [b70362] Add the python3 test.
 .gitignore 2025-11-03 effepivi effepivi [c7c4ba] Do not save .idea on the Git repo.
 .readthedocs.yaml 2025-01-23 effepivi effepivi [c0007d] Add file.
 BUILD.md 2025-07-16 effepivi effepivi [f72f6a] Rename files.
 BUILD.pdf 2025-07-16 effepivi effepivi [f72f6a] Rename files.
 BUILD.txt 2025-07-16 effepivi effepivi [f72f6a] Rename files.
 CHANGELOG 2026-02-24 effepivi effepivi [a4b2de] Add OpenMP backend.
 CMakeLists.old 2020-07-20 Franck Vidal Franck Vidal [856ddb] Build gvxr.
 CMakeLists.txt 2026-02-23 effepivi effepivi [eed4bb] Make it possible to compile gVXR without OpenGL...
 CODE_OF_CONDUCT.md 2026-01-30 Franck Vidal Franck Vidal [729d75] Add the code of conduct.
 CONTRIBUTING.md 2026-01-30 Franck Vidal Franck Vidal [75b434] Add content.
 CONTRIBUTORS 2025-07-29 effepivi effepivi [aff638] Add institutions.
 CTestConfig.cmake 2024-03-11 Franck Vidal Franck Vidal [048f43] Move the file to the root of the repository.
 LICENSE 2022-07-26 Franck Vidal Franck Vidal [275ab4] Work on pip install. It seems to work for Linux.
 Logo-transparent-large.png 2024-03-11 Franck Vidal Franck Vidal [5d9bcd] Add logo files.
 Logo-transparent-small.png 2024-03-11 Franck Vidal Franck Vidal [5d9bcd] Add logo files.
 Logo.png 2022-11-16 Franck Vidal Franck Vidal [47f2b1] Add the logo.
 README.md 2025-10-02 Franck Vidal Franck Vidal [1f5944] Update the README file.
 SECURITY.md 2026-01-30 Franck Vidal Franck Vidal [d0ee62] Add security policy.
 VERSION.txt 2026-02-03 effepivi effepivi [d3f262] Change the version to 2.1.0.
 architecture.dia 2020-05-12 Franck Vidal Franck Vidal [2343c0] Add architecture diagram.
 architecture.png 2020-05-12 Franck Vidal Franck Vidal [2343c0] Add architecture diagram.
 conanfile-manylinux2014.txt 2026-02-05 effepivi effepivi [b62b30] Use a text file to install dependencies.
 conanfile.txt 2026-02-16 effepivi effepivi [00854b] Can choose between Glad or Glew to initialise O...
 dependency_graph.dia 2020-05-12 Franck Vidal Franck Vidal [c13a04] Add the dependency diagram.
 dependency_graph.png 2020-05-12 Franck Vidal Franck Vidal [c13a04] Add the dependency diagram.
 edit_version.sh 2025-04-08 effepivi effepivi [83f851] Add missing file to the script.
 md2pdf.sh 2025-12-18 effepivi effepivi [005ad7] Prefix files and paths with "./" when using glob.
 pyproject.toml 2026-02-11 effepivi effepivi [3952c8] Add SWIG as a dependency.
 setup.py 2026-02-23 effepivi effepivi [eed4bb] Make it possible to compile gVXR without OpenGL...

Read Me

gVirtualXray (gVXR): Virtual X-Ray Imaging Library on GPU

What does gVXR do?

gVirtualXRay (gVXR) is a C++ library to simulate X-ray imaging.
It is based on the Beer-Lambert law to compute the absorption of light (i.e. photons) by 3D objects (here polygon meshes).
It is implemented on the graphics processing unit (GPU) using the OpenGL Shading Language (GLSL).

SimpleGVXR is a smaller library build on the top of gVirtualXRay.
It provides wrappers to Python, R, Ruby, Tcl, C#, Java, and GNU Octave.

What can you do with gVXR?

X-ray simulations created with gVirtualXRay have been used in a wide range of applications, including

  • real-time medical simulators,
  • proposing a new densitometric radiographic modality in clinical imaging,
  • studying noise removal techniques in fluoroscopy,
  • teaching particle physics and X-ray imaging to undergraduate students in engineering, and XCT to masters students,
  • predicting image quality and artifacts in material science, etc.
    gVXR has also been used to produce a high number of realistic simulated images in optimisation problems and to train machine learning algorithms, with applications in oncology and radiology in medicine as well as material science.

Further details are available in three community review articles:

Who is it for?

gVXR is an application programming interface (API).
It is for software developers who wish to simulate realistic X-ray images in realtime when photon scattering is negligible.
gVXR's features can be used in C++, Python, R, Ruby, Tcl, C#, Java, and GNU Octave.
To simplify the setting up of a simulation, a user-friendly JSON file format has been designed (note: for Python only at the moment).

If programming is not your thing, check out WebCT, a feature-rich environment for previewing and simulating X-ray scans on the web browser.

Is gVXR available for free?

Yes, gVXR is open source. Its source code is available under the BSD 3-Clause License. For details on use and redistribution please refer to http://opensource.org/licenses/BSD-3-Clause.

Is gVXR available as a package that can be deployed without building it?

Python wheels are available on Python Package Index (Pypi). For other programming languages, you will have to build gVXR from the source code.

Is gVXR code publicly available to download?

Yes. It is hosted in an established third-party source code repository called SourceForge.

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:

  1. Create a renderer (OpenGL context): gvxr.createOpenGLContext()
  2. 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();
  3. Spectrum:
    • monochromatic (0.08 MeV, i.e. 80 keV),
    • 1000 photons per ray,
    • gvxr.setMonoChromatic(0.08, "MeV", 1000)
  4. 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")
  5. 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), or
        • gvxr.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")
  6. 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?

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

# 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
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
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()

Awards & accolades

  1. 2nd place
    Eurographics 2009 - Medical Prize
    for "ImaGiNe-S : Imaging Guided Needle Simulation".
    DOI: 10.2312/egm.20091024
  2. Winner of Ken Brodlie Prize for best paper
    Theory and Practice of Computer Graphics 2009 (TPCG 2009)
    for "Simulation of X-ray Attenuation on the GPU".
    DOI: 10.2312/LocalChapterEvents/TPCG/TPCG09/025-032
  3. Winner of David Duce Prize for best short paper
    Computer Graphics and Visual Computing 2019 (CGVC 2019)
    for "Projectional Radiography Simulator: an Interactive Teaching Tool".
    DOI: 10.2312/cgvc.20191267
  4. Best poster presentation
    6th Dimensional X-ray Computed Tomography Conference (dXCT 2022)
    for "WebCT: Fully Featured Browser-Based Interactive X-Ray Simulations for Scan Planning and Training".
  5. Runner-up award for best student presentation
    Image-Based Simulation for Industry (IBSim-4i) 2023
    for "Creating Functional Digital Shadows of X-ray systems".
  6. 1st place
    CoSeC Impact Award 2023
    for "Digital twins of industrial XCT scanners".
    URL: https://www.cosec.ac.uk/impact/cosec-announces-impact-award-for-2023/
  7. Best Presentation Award
    International Symposium on Machinery and Mechatronics for Agriculture and Biosystems Engineering (ISMAB) 2024
    for "Enhancing Material Decomposition in spectral CT Imaging via Deep Learning".
  8. Best paper award for tomography outreach tools
    Developments in X-Ray Tomography XV, SPIE Optics & Photonics 2024
    for "X-ray simulations with gVXR as a useful tool for education, data analysis, set-up of CT scans, and scanner development".
    DOI: 10.1117/12.3025315
  9. 3rd place
    Dirk Bartz Prize for Visual Computing in Medicine and Life Sciences 2025 (Eurographics Medical Prize)
    for "X-ray simulations with gVirtualXray in medicine and life sciences".
    DOI: 10.2312/evm.20251974

Build and test status of the trunk

gVirtualXRay may be built from source using CMake. The status of the latest build can be found on CDash.

gVXR is cross-platform: it runs on

  • MS Windows(Intel architecture only, it might work on ARM architecture too),
  • GNU/Linux (Intel & ARM architectures), and
  • MacOS computers (Intel architecture only).

It supports GPUs from any manufacturer. It can even run on platforms without GPUs (in this case, be patient as the CPU will be used).

gVXR is scalable: it runs on

  • Raspberry Pi,
  • laptops,
  • desktop PCs,
  • supercomputers, and
  • cloud infrastructures, including:
    • Google Colab,
    • Code Ocean, and
    • STFC cloud.

Containerization using Docker is even possible.

It should be possible to run it on other platforms, but this has not been tested.

How to cite

If you use gVXR in your own applications, particularly for research & development, I will be grateful if you could cite the articles as follows:

  • Seminal paper: F.P. Vidal, M. Garnier, N. Freud, J.M. Létang, and N.W. John: Simulation of X-ray attenuation on the GPU. Proceedings of Theory and Practice of Computer Graphics 2009, Eurographics Association, Cardiff, UK (2009), pp. 25-32, doi: 10.2312/LocalChapterEvents/TPCG/TPCG09/025-032 <link>
  • First reference to gVXR as an opensource software: F.P. Vidal and P.-F. Villard: Development and validation of real-time simulation of X-ray imaging with respiratory motion. Computerized Medical Imaging Graphics, 49 (2016), pp. 1-15, doi: 10.1016/j.compmedimag.2015.12.002 <link>
  • Clinical validation study: J.L. Pointon, T. Wen, J. Tugwell-Allsup, A. Sújar, J.M. Létang, and F.P. Vidal: Simulation of X-ray projections on GPU: Benchmarking gVirtualXray with clinically realistic phantoms. Computer Methods and Programs in Biomedicine, 234 (2023), pp. 107500, doi: 10.1016/j.cmpb.2023.107500 <link>
  • Comprehensive review paper: Vidal, F. P., Afshari, S., Ahmed, S., Albiol, A., Albiol, F., Béchet, É., … Villard, P.-F. (2025).:
    X-ray simulations with gVXR in education, digital twining, experiment planning, and data analysis
    Nuclear Instruments and Methods in Physics Research Section B: Beam Interactions with Materials and Atoms, vol. 568, article 165804, doi: 10.1016/j.nimb.2025.165804
@article{POINTON2023107500,
    title = {{Simulation of X-ray projections on GPU: Benchmarking gVirtualXray with clinically realistic phantoms}},
    journal = {Computer Methods and Programs in Biomedicine},
    volume = {234},
    pages = {107500},
    year = {2023},
    issn = {0169-2607},
    doi = {10.1016/j.cmpb.2023.107500},
    author = {Jamie Lea Pointon and Tianci Wen and Jenna Tugwell-Allsup and 
        Aaron S\'ujar and Jean Michel L\'etang and Franck Patrick Vidal}
}

@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,
    doi = "10.1016/j.compmedimag.2015.12.002",
    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},
    publisher = {Eurographics Association},
}

@article{Vidal2025NIMB,
    author = {Vidal, Franck P. and Afshari, Shaghayegh and Ahmed, Sharif and Albiol, Alberto and 
        Albiol, Francisco and B{\'e}chet, {\'E}ric and Bellot, Alberto Corb{\'\i} and Bosse, Stefan and 
        Burkhard, Simon and Chahid, Younes and Chou, Cheng-Ying and Culver, Robert and Desbarats, Pascal and 
        Dixon, Lewis and Friemann, Johan and Garbout, Amin and Garc{\'\i}a-Lorenzo, Marcos and 
        Giovannelli, Jean-Fran{\c c}ois and Hanna, Ross and Hatton, Cl{\'e}mentine and Henry, Audrey and 
        Kelly, Graham and Leblanc, Christophe and Leonardi, Alberto and L{\'e}tang, Jean Michel and 
        Lipscomb, Harry and Manchester, Tristan and Meere, Bas and Michelet, Claire and Middleburgh, Simon and 
        Mihail, Radu P. and Mitchell, Iwan and Perera, Liam and Puig, Mart{\'\i} and Racy, Malek and 
        Rouwane, Ali and Seznec, Herv{\'e} and S{\'u}jar, Aaron and Tugwell-Allsup, Jenna and 
        Villard, Pierre-Fr{\'e}d{\'e}ric},
    doi = {10.1016/j.nimb.2025.165804},
    journal = {Nuclear Instruments and Methods in Physics Research Section B: Beam Interactions with Materials and Atoms},
    keywords = {X-ray imaging; Computed tomography; Simulation; GPU programming; Digital twinning; Registration; Machine learning},
    pages = {165804},
    title = {{X-ray simulations with gVXR in education, digital twining, experiment planning, and data analysis}},
    volume = 568,
    year = 2025
}

Scientific and Industrial Collaboration

If you are interested in any form of collaboration (e.g. to develop your own application), e.g. research papers or grant proposals, drop the package maintainer an email.

© Copyright 2011-2023, Dr Franck P. Vidal, School of Computer science and Electronic Engineering, Bangor University. All rights reserved

© Copyright 2024-, Prof Franck P. Vidal, Computed Tomography, Scientific Computing, Science and Technology Facilities Council (STFC). All rights reserved

MongoDB Logo MongoDB