Closed ginsanity15 closed 6 years ago
The noise you add is white according to this line:
data += odl.phantom.white_noise(ray_trafo.range) * np.mean(data) * 0.1
and the MLEM solver is only defined for positive values, but this will give you negative values, causing it to diverge. Perhaps we should have a check for this in the MLEM solver.
If you actually add poisson noise according to e.g.
data = odl.phantom.poisson_noise(data) # data is the "lambda" parameter of the noise
the solver should work.
Please also note that you typically don't want to manually set the sensitivities
parameter. It is computed automatically.
Okay I see, thank you for pointing out my problem. I just reconstructed projection with the real poisson noise and the solver works fine. Thanks for the recommendation on the sensitivities as well, I was just wondering if miracle would happen if I tune "sensitivities" a little bit.
Great to hear! In general the sensitivites parameter is given since in applications they are typically measured separately. For simulation studies you should just compute them automatically.
hi,do you know how to simulate the low-dose data
hi,do you know how to simulate the low-dose data
You need to check the physics to get realistic values. Here are the steps:
Here's some Python pseudocode:
intensity = 10000 # or whatever value makes sense
attenuation_coeff = # <- code for phantom creation goes here
proj_data = ray_trafo(attenuation_coeff)
noise_free_data = intensity * np.exp(-proj_data)
noisy_data = odl.phantom.poisson_noise(noise_free_data)
A complete example that does all this (but more complex, for spectral CT) is here -- check out the "A complete example" section.
For a given phantom composition (let's say water, bone and fat) get the realistic values for the attenuation coefficients, for instance from NIST. There are libraries for this, e.g., physdata.
Of course, you can also just play around with values, e.g., take an odl.phantom.shepp_logan
phantom and multiply it with some constant that gives you a workable result, like np.exp(-proj_data)
is neither extremely close to 1 everywhere (too little contrast) nor very close to 0 anywhere (too dense object, "photon starvation").
Just as a general pointer, the mass attenuation coefficient of water at typical x-ray energies is about 0.2 cm^2 g^-1.
As an example, this generates data with that coefficient and reconstructs it using FBP, with units carefully written out
import odl
import numpy as np
attenuation_coefficient = 0.2 # unit is cm^2/g
intensity = 50000 # number of photons per pixel
space = odl.uniform_discr([-12.8, -12.8], [12.8, 12.8], [256, 256]) # units in cm, 256 pixels
phantom = odl.phantom.shepp_logan(space) # units is g/cm^3
attenuation = phantom * attenuation_coefficient # Unit is cm^-1
# The ray transform respects the units given to it.
# Since our input has units cm^-1 and we take the line integral of it, the output is unitless
ray_trafo = odl.tomo.RayTransform(space, odl.tomo.parallel_beam_geometry(space))
proj_data = ray_trafo(attenuation)
noise_free_data = intensity * np.exp(-proj_data) # unit is photons per pixel
noisy_data = odl.phantom.poisson_noise(noise_free_data) # unit is photons per pixel
# Convert g / cm^2
log_noisy_data = -np.log(noisy_data / intensity) / attenuation_coefficient
# FBP is "inverse" of line integral, hence result has units g / cm^3 as expected
fbp_op = odl.tomo.fbp_op(ray_trafo, filter_type='Hann')
fbp = fbp_op(log_noisy_data)
log_noisy_data.show('log_noisy_data')
fbp.show('fbp window', clim=[0.95, 1.15])
I was trying to perform CT reconstruction with statistical solver: mlem. It works fine when the projection is noise-free. However, the reconstruction result will not converge after I add bit possion noise to the projection data. I have pasted my code below, please let me know if I have missed something here.
Edit: @adler-j typeset code