jrkerns / pylinac

An image analysis library for medical physics
MIT License
145 stars 94 forks source link

pf.analyze() throws an exception with Varian Truebeam picket fence file #470

Open ekamperi opened 7 months ago

ekamperi commented 7 months ago

Describe the bug Analyzing a picket fence dicom file obtained from a Varian Truebeam linac throws an exception during the detection of the left edge detection.

(dicom) ➜  ~ python
Python 3.11.4 | packaged by conda-forge | (main, Jun 10 2023, 18:08:41) [Clang 15.0.7 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> from pylinac import PicketFence
>>> pf = PicketFence('/Users/stathis/Downloads/crash.dcm')
>>> pf.analyze()
/Users/stathis/miniforge3/envs/dicom/lib/python3.11/site-packages/numpy/core/fromnumeric.py:3504: RuntimeWarning: Mean of empty slice.
  return _methods._mean(a, axis=axis, dtype=dtype,
/Users/stathis/miniforge3/envs/dicom/lib/python3.11/site-packages/numpy/core/_methods.py:129: RuntimeWarning: invalid value encountered in scalar divide
  ret = ret.dtype.type(ret / rcount)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/stathis/miniforge3/envs/dicom/lib/python3.11/site-packages/pylinac/picketfence.py", line 597, in analyze
    window = self._get_mlc_window(
             ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/stathis/miniforge3/envs/dicom/lib/python3.11/site-packages/pylinac/picketfence.py", line 693, in _get_mlc_window
    left_edge = max(int(approx_idx - spacing / 2), 0)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: cannot convert float NaN to integer
>>>

I tried with invert=True and also with LEFT_RIGHT and UP_DOWN orientation. Same result.

To Reproduce Please find the faulty picket fence dicom file here.

Expected behavior Pylinac should either succeed in analyzing the picket fence file or display some more informative message to guide the user.

Screenshots This is the orientation of the picket fence image data:

image

Additional context For what is worth this happens only in static picket fence dicom files. When obtaining a picket fence over an arc beam, pylinac succeeds. Happy to provide any further information that could help to figure out what's going on.

crcrewso commented 7 months ago

That image does not look like a successful picket fence delivery. I'm only seeing horizontal streaks, not the expected vertical dose bars.

ekamperi commented 7 months ago

Indeed. However I get the exact same behavior from a seemingly valid picket fence.

image

I added some debug print()s in picketfence.py and it appears that spacing isn't calculated properly. If I hardcode it, pylinac doesn't throw but it doesn't recognise all the fences. E.g.

pf_good.analyze(picket_spacing=None) throws but pf_good.analyze(picket_spacing=50) succeeds though only one fence is detected:

image
jrkerns commented 7 months ago

I'm not able to access your link.

ekamperi commented 7 months ago

I'm not able to access your link.

Apologies, I fixed the link. It should work now.

EDIT: I guess GitHub is blocking external links that are not https? Anyway, copying and pasting manually http://test2.ogkologia.gr/picket.dcm should work.

jrkerns commented 7 months ago
pf = PicketFence(<file>)
pf.analyze(required_prominence=0.1)
pf.plot_analyzed_image()

This works for me.

The reason it won't analyze is due to the narrow y-range of the MLCs. Opening the Y-jaws more will generally analyze without any extra parameters. I'll play around to see if I can auto-detect the initial picket locations better out of the box. Thanks.

alanphys commented 2 months ago

Hi James

I am getting the same error with the HD Millenium MLC with the attached file. I see in the predefined MLC types the HD Millenium MLC is defined as: HD_MILLENNIUM = { "name": "HD Millennium", "arrangement": MLCArrangement([(10, 5), (40, 2.5), (10, 5)]), } #:

The Varian Truebeam system overview gives the HD Millenium arrangement as: image Shouldn't the MLCArrangement be (14,5), (32, 2.5), (14, 5)] ?

However I tried the following:

>>> mlc_setup = MLCArrangement(leaf_arrangement=[(14,5), (32, 2.5), (14, 5)])
>>> pf = PicketFence('/home/alanphys/Sites/VP/Static.dcm', mlc=mlc_setup)
>>> pf.analyze()

and

>>> mlc_setup = MLCArrangement(leaf_arrangement=[(32, 2.5)])
>>> pf = PicketFence('/home/alanphys/Sites/VP/Static.dcm', mlc=mlc_setup)
>>> pf.analyze()

as well as

>>> pf = PicketFence('/home/alanphys/Sites/VP/Static.dcm', mlc='HD Millennium')
>>> pf.analyze()

and they all gave the same error. Your workaround above worked though. The MLC arrangement doesn't seem to affect the analysis. StaticNew.zip

Regards Alan

jrkerns commented 2 months ago

Ugh, you're right. How embarrassing 🤦. I'll adjust that in the next release