-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CPU-based simulation of x-ray projections and reconstruction #22
Conversation
Signed-off-by: JSCallaghan <jcc23grt@bangor.ac.uk>
Signed-off-by: JSCallaghan <jcc23grt@bangor.ac.uk>
Signed-off-by: JSCallaghan <jcc23grt@bangor.ac.uk>
Hi @JSCallaghan - many thanks for your contribution from the CIL user meeting! We will try and review over the next couple of weeks :) |
Hi @JSCallaghan, Nice to see you took the time to create a CIL/gVXR User contribution. Below are a few suggestions:
from gvxrPython3.utils import loadSpectrumSpekpy
# gvxr.addEnergyBinToSpectrum(scaVol, "keV", 1)
loadSpectrumSpekpy(scaVol);
gvxr.computeCTAcquisition("", # Where to save the projections
"", # Where to save the screenshots
numPro, # Total number of projections
0, # First angle
False, # Include the last angle
360, # Last angle
0, # Number of flat images
0, 0, 0, "mm", # Centre of rotation
*gvxr.getDetectorUpVector()) # Rotation axis
projSim = np.array(gvxr.getLastProjectionSet())
# # Define the number of projections, along with the angle step
# angSte = endAng / numPro
# # Pre-create our results array with the size of our detector
# projSim = np.ndarray((numPro, numPixY, numPixX))
# # Rotate our object by angSte for every projection, saving it to the results array.
# for i in range(0, numPro):
# # Save current angular projection
# projSim[i] = gvxr.computeXRayImage()
# # Rotate models
# gvxr.rotateScene(angSte,0,0,1)
# Don't forget, we need to use flatfield normalisation on the radiographs to get the correct attenuation values!
# Because our flatfield and darkfield are perfect, all we need to do is divide by the total energy
projSim /= gvxr.getTotalEnergyWithDetectorResponse() |
Hi @effepivi, thanks for the suggestions.
|
Hi @JSCallaghan - heard that you spoke to @effepivi who confirmed that the GVXR simulation was being done on GPU but the CIL part on CPU. I have changed the text to reflect this. Indeed, we triple-checked and although ASTRA has CPU forward and backward projectors for a 2D fanbeam geometry it doesn't have an FBP implementation. Thus we can do iterative methods but not an FBP reconstruction. I also clarified this in the text. |
Thank you very much @JSCallaghan for this very nice notebook and @MargaretDuff and @effepivi for commenting and processing, I've taken a quick look and the notebook looks really great. As I am not so familiar with gVXR, I will leave the formal reviewing/approval to someone else (@effepivi?) but can provide a few minor comments:
Thank you again for this excellent addition to the showcase. Next step - a tiny code contribution to CIL itself? :) |
@jakobsj & @JSCallaghan import base64
plot.fetch_screenshot();
k3d_screenshot = plot.screenshot;
data = base64.b64decode(k3d_screenshot);
with open("k3d_screenshot.png", "wb") as fp:
fp.write(data);
fp.flush();
fp.close(); However, due to some asynchronous behaviours, it is possible that the code above needs to be called twice (I often have an empty file on the 1st try). BTW, you can also use k3D to do some volume rendering in the notebook: bounds = [0, ig.voxel_num_x * ig.voxel_size_x, 0, ig.voxel_num_y * ig.voxel_size_y, 0, ig.voxel_num_z * ig.voxel_size_z]
np_recons = recons.as_array()
k3d_volume = k3d.volume(np_recons, bounds=bounds)
plot = k3d.plot()
plot += k3d_volume
value_range = [np.min(np_recons), np.max(np_recons)]
k3d_volume.alpha_coef = 5
k3d_volume.color_range = [value_range[0] + (value_range[1] - value_range[0]) / 3, value_range[1]]
plot.display() |
Thanks @effepivi and @jakobsj, I have:
@effepivi - I didn't understand your comment on volume rendering the reconstruction - the reconstruction is just a 2D slice? |
Text:
If you end one line with a full stop, the next one must start with a capital letter. The use of full stops (or semicolons as a matter of fact) in bullet point lists is contraversial. They're not "needed". However, they can be used for inclusivity as it helps people see when an item is finishing and when another one is starting. I was disability officer, and we were told at the time to recommend collleagues something like that to make it clear for everyone:
In any case, being consistent is what matters the most. Code:
projDiff = 100*(projSim[0]-projRead[0])/projSim[0])
limit = max(abs(projDiff.min()),projDiff.max())
show2D([projSim[0], projRead[0], projDiff],title=["sim","sim_read_write_"+dataWriteMethod,"difference (in %)"],\
cmap='seismic',num_cols=3,fix_range=[(0,1),(0,1),(-limit,limit)], size=(9,3))
Other than that, it looks great, I like it! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving after a review from Jakob and 2 reviews from Franck
Describe your contribution
Checklist when you are ready to request a review
Note: for an example of a contribution, where a license header, description, data link and CIL version has been added, please
see: example_contribution