pylinac icon indicating copy to clipboard operation
pylinac copied to clipboard

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

Open ekamperi opened this issue 7 months ago • 7 comments

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.

ekamperi avatar Nov 14 '23 19:11 ekamperi

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

crcrewso avatar Nov 14 '23 19:11 crcrewso

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

ekamperi avatar Nov 14 '23 21:11 ekamperi

I'm not able to access your link.

jrkerns avatar Nov 15 '23 02:11 jrkerns

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.

ekamperi avatar Nov 15 '23 05:11 ekamperi

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.

jrkerns avatar Nov 15 '23 16:11 jrkerns

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

alanphys avatar Apr 12 '24 08:04 alanphys

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

jrkerns avatar Apr 12 '24 14:04 jrkerns