LLNL / LEAP

comprehensive library of 3D transmission Computed Tomography (CT) algorithms with Python and C++ APIs, a PyQt GUI, and fully integrated with PyTorch
https://leapct.readthedocs.io
MIT License
119 stars 12 forks source link

questions about function set_truncatedScan #56

Closed router-2001 closed 4 months ago

router-2001 commented 5 months ago

Hi !

I run the 'd01_standard_geometries' with my own dataset, and in those 'Detector Scanning Blind Zone',i am wondering should it be totally dark ? Attached are the codes including CT detector and volume information and reconstruction results.

I think the part above the yellow cross in the ‘ XZ 384.jpg ‘ image is supposed to be the result of a zero-padding or extrapolation ? should it be theoretically black? If not , can you explain how the function ' leapct.set_truncatedScan(True) 'work ?

question.zip

kylechampley commented 5 months ago

Hello. The truncated scan setting only effects how the ramp filter step of FBP is performed. It can be used to help mitigate artifacts when the object is too wide for the detector, i.e., the projections are truncated on the right and/or left sides of the detector. It has no effect if the projections are truncated on the top and/ or bottom of the detector (the so-called long object problem). The sample images you provided seem to indicate that your object does not extend past the right and/ or left sides of your detector, so I don't think this is necessary for you to use.

Now when you perform an FBP reconstruction in LEAP, the backprojector performs zeroth order extrapolation off the bottom and top of the detector. This helps mitigate artifacts at the axial extents of the object. This extrapolation has no end and LEAP will continue to assign values at slices that go way beyond the detector if you specify it that way. This may seem weird, but this is actually helpful when performing iterative reconstructions for the long object problem because these edges can be forward projected and then subtracted off the measured data (the Zeigler method) to prepare the data for iterative reconstruction which mitigates artifacts at the edge slices.

The code you provided shows that you specified a volume that extends well past the axial field of view of your system and thus provides these strange looking artifacts.

Hopefully this all makes sense. It may also help me if you could explain what you are trying to do.

hws203 commented 5 months ago

About this issue, I also see it on my sample of micro-coil too. At my case, I thought that this is not actual weird, so I just masked out the outside area with black pixel filling on slices after back-projection.

hws203 commented 5 months ago

@kylechampley Please check the difference between the laminography and standard cone beam.

  1. Laminography case: micro-coil-leap_01

  2. standard cone beam case: micro-coil-leap_02

As you can see the areas of none valid(A,B,C,D) have default different pixel, the first is white and the last is black. Could you make it same as like standard cone beam case at laminography too ? For regeneration this issue, please change the sod = 1100 to sod=700, then you can see the almost same issue at your origin d32_laminography.py script.

micro-coil-leap_03

kylechampley commented 5 months ago

OK, it looks like there are multiple issues being confused here. In the original post for this issue, the images shown were coronal slices and vertical line structures were caused by the zero-th order extrapolation in the backprojection step of FBP. Note that this is only with FBP; the backprojection command does not do this.

The images above appear to be axial slices. The difference in these images is caused by the circular field of view mask. By default parallel-, fan-, and cone-beam geometry apply such as mask, but modular-beam does not. If you want the modular-beam geometry reconstruction to apply such a circular mask, the use leapct.set_diameterFOV(d), where d is the appropriate value. On the other hand if you have a parallel-, fan-, or cone-beam geometry and you do not want this mask applied just do this: leapct.set_diameterFOV(1.0e16). Here we have just give a huge value to the diameter of the field of view to make sure no mask would be applied.

With regards to the original post: I will generate a demo script to show why this behavior is useful.

kylechampley commented 5 months ago

Here is an example of why this extrapolation is performed. The images below show coronal slices of the FORBILD head phantom reconstructed with FDK. The image on the left does not use extrapolation in the backprojection, while the image on the right uses the standard extrapolation in FDK. Notice that the image on the left has four black triangular regions at the edge slices, while the image on the right has uniform intensity everywhere. As I said before there are also uses of this when prepping data for iterative reconstruction. I'll make this demo script later this week. image

hws203 commented 5 months ago

Yes, your set_diameterFOV() works at this case, But I can see that some residual white circle at the edge of this radius. Is there any wrong point at my calculation of the FOV. Below is my calculation.

  1. calcuation at C++ : pLeap->set_rFOV(0.5 (numCols - 1) pixelSize*sod/sdd);
  2. Result of axial slice : micro-coil-leap_04
hws203 commented 5 months ago

I added some extra minus radius at my calculation, then it looks good. =>pLeap->set_rFOV(0.5 (numCols - 20) pixelSize*sod/sdd); I do not know it is normal. micro-coil-leap_05

Second calculation => int sRadius = std::min(numCols, numRows); pLeap->set_rFOV(0.5 (sRadius - 1) pixelSize*sod/sdd);

I used the different width and height detector so I have to use the shorter side length for this calculation(with faster FBP). micro-coil-leap_06

kylechampley commented 5 months ago

Wow, it looks like you are using LEAP directly through C++. That's cool. The reconstructable field of view calculation depends on the scanner geometry. If you want to see how LEAP does this automatically see parameters::rFOV()

hws203 commented 5 months ago

Yes right, I am using LEAP directly at C++ and also using the native C++ simple optimizer which supports powell method. I can see that this minimizer can find more accurate value rather than the sweep method. Thanks for your advice.

kylechampley commented 4 months ago

@router-2001 did I answer your question/ resolve your issue?

router-2001 commented 4 months ago

@router-2001 did I answer your question/ resolve your issue?

yes,it makes sense.thanks for your time!