MLC position data in trf file

First of all, thank you for giving me an opportunity to join this community.
I would like to say that I’m not accustomed to using a python.
Accidentally, I found out this site and pymedphys. I opened elekta’s versa hd with trf2csv file. But I have a problem. The MLC position data from trf file is not matching with them in a DICOM file. I’m very embarrased.
Is there a special coordinate? Could you tell me the trf file structure? I just do a research on a mechanical errors.

Hi @Cool :slightly_smiling_face:,

Welcome to the PyMedPhys community :rocket:.

First of all, thank you for giving me an opportunity to join this community.

You are more than welcome :slight_smile: our pleasure :slight_smile:.

I opened elekta’s versa hd with trf2csv file. But I have a problem. The MLC position data from trf file is not matching with them in a DICOM file.

The TRF file format is the “bi-polar” coordinate system. It is going to be different to DICOM. You can convert your DICOM files to the same coordinate system by running the following:

import pymedphys

dicom_delivery = pymedphys.Delivery.from_dicom('path/to/dicom/plan')
trf_delivery = pymedphys.Delivery.from_trf('path/to/trf')

dicom_delivery.mlc  # Here is the bipolar version of the DICOM MLCs
trf_delivery.mlc  # Here is the TRF MLCs

Also, if you’re interested in doing comparisons between DICOM files and TRF files, I actually have built an online application to do just that. If you go to https://app.pymedphys.com then click on “MetersetMap Comparison” you can then upload a DICOM plan file and a TRF file and it will compare the two for you.




image


Let me know how you go :slight_smile:

Thank you for your kindness.
Today, I tried it and partially solved the problem.
The “MetersetMap Comparison” don’t work. I followed up your sceern shots.





I marked the procedures on the images.
I opened the same patient’s DICOM file as the “trf” file.
I typed the problems on the images.


Also, I want to know about the “from_dicom” and “from_trf” functions.
For examples, I’d like to know about what they give for the return values and what the return values include.
How can I match the number of MLC data in dicom and the number of MLC data in "trf " which is greater than before?

Best regards.

Hi @Cool,

Thank you for that bug report. Massively appreciated :slight_smile:

I think I should have fixed the issue you reported. Can you go to the following link and give it another try?

https://app.pymedphys.com/?app=metersetmap

Cheers,
Simon

That’s not so simple. The TRF is indexed by timestamp, the DICOM by control points. So fundamentally they won’t align row-to-row. The sign being changed for the TRF file makes sense as TRF records MLCs and Jaws as “how far are they open away from the centre of the collimator”. So a 10cm x 10cm field would read 50.0 and 50.0 on both Jaws for example.

Also, I want to know about the “from_dicom” and “from_trf” functions.
For examples, I’d like to know about what they give for the return values and what the return values include.

The output from “from_dicom” and “from_trf” is a namedtuple. You can see what items are inside it by calling the following:

In [1]: import pymedphys

In [2]: delivery = pymedphys.Delivery.from_dicom('979797_VMAT.dcm')

In [3]: [item for item in dir(delivery) if not item.startswith('_')]
Out[3]: 
['collimator',
 'combine',
 'count',
 'from_dicom',
 'from_icom',
 'from_logfile',
 'from_monaco',
 'from_mosaiq',
 'from_trf',
 'gantry',
 'index',
 'jaw',
 'merge',
 'metersetmap',
 'mlc',
 'monitor_units',
 'mu',
 'mudensity',
 'to_dicom']

Thank you for your advice.
I extracted the row data from the TRF file when the control point in the Control point/Actual Value (None) ,which is in the TRF file, are changed. The method that I made is that I changed TRF file into CSV file and read with the ‘pandas’.
I grouped them with dataframe’s groupby() function, after that, I used the dataframe’s first() function to extract the row data. The data in the files almost aligned.
But there is a problem which are mlc’s position problem. The number of leaves from 1 to 21 and from 59 and 80 are not matched. You can check it out, right before I uploaded the images.
I wonder why the units of table are not ‘mm’ but ‘deg’, “Table Longitudinal/Scaled Actual (deg)” in the TRF file.
The last question is what “Dlg Y2/Scaled Actual (mm)” in the TRF file are.

I’m very impressed by your sincere answers. Also, I’m sorry for taking your precious time.

With best regards.
Pilsu Kim.

Yeah, this decoder is actually based on a reference implementation. I chose to match to the reference implementation where the units were wrong. There are some other weird quirks due to opting to be as close to the original as possible.

Would you be able to provide some example data and python script that replicates this so that I can run it locally to try and see what’s going on?

If you’d be interested, I’d massively appreciate if you’d consider writing up a how-to guide which can be placed in the following location to help future new users in your shoes :slight_smile: with exactly these problems you’re having.

https://docs.pymedphys.com/howto/index.html

I find some of the best how-to guides are written by new users as new users really understand what new users need to know.

Today is Friday here in Korea. A weekend starts tomorrow. :sweat_smile:

It takes time to modify the python script. Could you wait for a few days?
I’ll upload the file.

Have a good weekend!!!

Oh certainly, I’m not making any promises about my responses being prompt :slight_smile:. I don’t expect you to be making promises like that either :slight_smile:.

It’s been five days since we had a discussion.
I’ve been a little bit busy.
I uploaded the zip file.
you just type “python3 main.py on linux” or “python main.py on window”.
The result file will be saved in the data folder and its name is “final.csv”.
As you can see it, the mlc leaves position’s not matching well from one to about 20 and from 60 to 80.
The code is not good.
I am a novice on python.
Please, check it.
Added file : test.zip (1.8 MB)
Best regards!!!

Hi @Cool,

I’ll have a look :slight_smile:, there might be a little bit of a delay on this one, I have to juggle a few priorities :slight_smile:.

Cheers,
Simon

Hi @Cool,

Just letting you know that this keeps getting bumped down my priority list and next week I’m going on leave for a while without any internet connection. …so… chances are I won’t be getting back to this for a couple of months at this rate.

If someone else wants to jump in and see if they can help, that’d be awesome :slightly_smiling_face:

Sorry about that,
Simon

It’s okay, Simon.
You don’t mind it.

I’ve also been busy studying python, DICOM and elekta versa HD.

The code is temporary and has some significant errors.
I’ll correct it or find a different way.
A few weeks later, see you again.

All the best
Pilsu

2021년 2월 3일 (수) 오전 3:39, Simon Biggs via PyMedPhys <pymedphys@discoursemail.com>님이 작성:

Hi Pilsu ( @Cool ).
I notice that your sample code is going directly to a low level private module function to convert to csv.
Perhaps if you used the public method trf.read(…) (which maps down to _trf.decode.trf2pandas(…) after few redirects/aliases), you might get better results, because there is code in there that addresses coordinate system conversion.
If you want to dump the pandas DataFrame to CSV, I understand there is a method for that in pandas.

I’d also like to encourage you to avoid uploading data (e.g. DICOM) that might have any Private Health Information. PyMedPhys has both anonymisation and pseudonymisation available either form the command line interface, public API, or even one of the streamlit apps (although you should run that locally instead of using the “public demo web site” if you are going to pseudonymise data so the original PHI never leaves your facility).

Hope this helps. If you need further assistance, I can try to help, but I have limited time outside of my own work…

Above all, thank you for your attention and advice.
I’ve been very busy these days. I have to write a paper and study something to solve this problem.
I’ve just started my life as a medical physicist.:smiley:
It’s my mistake about a DICOM file which contains the private information.
I forgot to erase them.
A few days later, I’ll have to check this problem again and ask some questions to you.

Best regards
Pilsu.

2021년 2월 13일 (토) 오전 8:45, Stuart J Swerdloff via PyMedPhys <pymedphys@discoursemail.com>님이 작성:

Hello Sir,
I have just read your post about MLC positions, and i am wondering if you could explain how to extract MLC position data from DICOM files. I would greatly appreciate any insights or guidance you could provide based on your experience.

Hi @Yassir_El_Ghazi!

If after you import pymedphys, the following should allow you to pull info out of DICOM:

pymedphys.Delivery.from_dicom

Could you have a play with that function and then report back how you went? It would be great to have a documented solution for the next person :slight_smile: