Picket fence - flipped image

Hi, James!

I was playing around with your picket fence module trying to make it work with Elekta 160 mlc. I noticed a possible problem with plotting. I believe that the image you get with plot_analyzed_image() is flipped upside down. I have a picket fence which is slightly rotated and I know that the errors are on the bottom picket, but pylinac gives me a mirrored image.
Can you confirm this?

Best regards,

picket fence pylinac.dcm (2 MB)

Unfortunately, I can’t confirm this since I don’t have an Elekta machine. It’s very possible that this is the case, but I don’t have any other elekta images to compare against. If you have more images I’d be happy to add analysis of the Elekta 160 leaf head (Agility right?) to pylinac.


Yes, it’s the Agility MLC head. The image I attached was taken with iViewGT on a VersaHD machine. Unfortunately, on Elekta machine you cannot get all the leaves on the image, because the imager is too far away from the head. And also, the picket width cannot be smaller than 5 mm. Oh, and doing it in dynamic mode (sliding window IMRT) is like playing the lottery. You never know when the imager will stop acqusition at the first beam interruption. But … there is hope.

If you try analyzing the image I have attached with pylinac, you should be able to get something out. MLC numbers will be wrong, but you should be able to notice that the plotted image is upside down if you compare it with imshow(pf.image.array). The erroneous pickets should be at the bottom. Well, at least I am getting it wrong.

I found on the internet a sample image from a Varian machine, it may have come from you demo images, that to me shows the same problem. Pylinac turns it upside down.

I hope you will not mind if I take the liberty of inspiring you to generalize picketfence module over some other MLCs. I have attached a modification of your module to show you what I was trying to do. I modified some parts of the code to allow the right MLC numbering. Instead of hdmlc parameter, the function analyze() now takes the argument mlc_type which can be set to “Elekta_160”, “Elekta_80”, “Varian_120”, “Varian_120HD” and “Varian_80”. These are the MLCs that we have at our institution. I only tested it on my beloved VersaHD, and the numbering seems ok.
I can give you more images for this head type if it would help.


EPID-PF-LR.dcm (1.5 MB)

picketfence_modified.py (40.5 KB)

Thank you so much for the suggestion and the modified code. I’ll definitely take a look at it and try to work it in. I agree, generalizing the picket fence analysis to work on more MLC models would be great; I’ve just never had access to anything other than Varian so I couldn’t really do much testing on other MLC types. If I had several images (esp. different SIDs & machines) I’d be comfortable adding Elekta Agility into the PF mix! I’ll take any images you have. Keep up the good work.


I’m new to Pylinac, but we would really like to use the PicketFence for our Elekta Agility MLCs. I’ve tried using the modified code Denis posted above (I can’t use the original module with the Elekta) but I just get a variety of error messages including max() arg is an empty sequence or that something is an empty slice. I don’t know whether it’s just something wrong with my image or something wrong with the plan I made and delivered. I would very much appreciate any suggestions.
I attach one of the EPID images so you can tell me what I’ve done wrong!!
Thanks very much for your help,

RI. (2 MB)

Hi Sally,

I tried running the modified script on your image, but I could not make it work. Right now I cannot pinpoint the problem.

But I can share with you how I do the test. First, I have modified the original pylinac script a bit more (see attachements). In the first modification I have made some mistakes - I don’t remember what they were.

I am uploading the iCOM CAT file that you can use to do the test on your beloved linac. You can send the beam to the linac via iCOM CAT which is usually available on all Mosaiq Sequencers. You can then send the beam directly to service mode where you can use it. If you are not familiar with iCOM CAT program, please contact me. If you do the test with this beam, then the modified pylinac script will work.

Best regards,

picketfence_modified.py (40.8 KB)

Picket Fence 0.5cm DMLC.efs (44.8 KB)

Thank you very much! I will test this. Have a lovely day :slight_smile:

nobody expects the.png

Hi Denis,

Can you share with me how you create the picket fence test for agility MLC? and how to upload the CAT file through mosaiq sequencer to linac machine ??

appreciate and thank you!


Hi Hooiyin,

I manually created the control point sequence in iCOM CAT. It is a program that is usually used during acceptance and was made by Elekta to communicate with Integrity via iCom. The procedure is such:

  1. Make sure that Mosaiq is not running on the sequencer. The linac console (Integrity) should be running in clinical mode waiting for external prescription.

  2. Run the iCom Cat program. You may find it on the sequencer computer under \Program Files\Elekta etc. If you cannot find it, contact Elekta support portal.

  3. In the icom cat program load and send to the linac the beam that I have attached to this thread. It works only for Agility so do not use it on other linacs. You may have to change the serial number of your linac in the icom cat file though.

  4. In iView prepare to capture a single image.

  5. Start the beam.

If Integrity is showing invalid prescription, check all the parameters in icom cat. Normally you just change the linac id and everything should work.

This icom cat beam that I created for the picket fence test works only on Agility linacs capable of dynamic imrt. But people can create other beams, like stepnshoot, if their linac does not support dynamic imrt. Only be careful. Sometimes Integrity does not cope well with erroneus beams, ie it may crash and then you will have to restart the linac.

Best regards

Dne ponedeljek, 21. avgust 2017 09.53.24 UTC+2 je oseba hooi yin Lim napisala:

Hi Dennis

May I have your email to send you 2 Agility Picket Fence to help analyse.

We encountered errors using you codes.

Thank you.


A note to all: Since I use this modified code via a simple web app that I connected to a dicom server (orthanc) to analyze the images, I had to modify James’s code for plotting images. If one is using it standalone, then one may see an erroneus superposition of leaf bars and the grayscale image of the pickets. I reverted this modification. A more familar version is in the attachment. Sorry for that.


Dne sreda, 23. avgust 2017 16.35.37 UTC+2 je oseba LipTeck Chew napisala:

picketfence_modified.py (39.4 KB)

Hi Denis and all,

Thank you Denis for modifying it. I believe all ELEKTA users can benefit from this. I summarise it as below:

Simply copy the picketfence_modified.py file into the pylinac folder nested under site-packages e.g.

Begin a typical session this way:

from picketfence_modified import PicketFence


Does any one uses tiff image to evaluate picket fence?
I do not have portal image system, I use gafchromic films.
Thanks for helping


I’m having some issues trying to analyze a Picket Fence from an Elekta Synergy machine with 1cm MLC.
I follow the tutorial in https://pylinac.readthedocs.io/en/stable/picketfence.html, and I get the error ZeroDivisionError: division by zero.
If I set pf.analyze(invert = True), then I get ax() arg is an empty sequence.
If I use the modified code attached by Denis, I get AttributeError: ‘PicketFence’ object has no attribute ‘results’ or ValueError: max() arg is an empty sequence when using pf.analyze(invert = True).
I have modified the dicom pixel array, but still same results.
Any help would be great.

PF.dcm (2 MB)

PFmodified.dcm (2 MB)

So using the original image there are two issues: 1) the usual Elekta pixel column issue. This is an error strictly limited to Elekta that for unknown reasons sets the 0th column (far left) to some crazy high value. 2) The pickets are too close to the field edges. This is technically a bug in pylinac. The initial pickets are found and then for each MLC pair a window to the left & right (or up/down) is searched. If the picket location is too close to an edge the window will be outside the image bounds. Unfortunately, bounding the window will cause problems down the line for the far left picket due to offsets being applied later. The following will work for your original image that addresses both issues. I will test the fix for issue 2) to see if I can apply it to the library. In the future, I would recommend moving the pickets further from the image edge.

See this gist for a script that addresses the issues.

Let me know if you run into any issues.

That worked perfectly.

Thank you very much!

Hello again.

I have found another problem.
We also have a Clinac 2100 CD at our institution. I did two PF test in the EPID. The delivered plans were the same, but the MV panel wasn´t exactly in the same position. The dicom images are almost identical.
The PF module worked for the first one but the second fails.

PFClinac1.dcm (385 KB)

PFClinac2.dcm (385 KB)

You have an uncanny ability to generate weird images. I’ve never seen EPID images where the left and right areas were uniformly the same value. It’s like the left and right edges were stretched or something. While the two images are similar, the left and right, weird uniform background areas are slightly different and the image inversion checker is getting different results for the two images. Anyway, you can analyze the second image by doing the following:

pf = PicketFences(‘…’)
pf.analyze(invert=True, orientation=‘updown’)