Ignore ValueError for comma in VR DS?

58 views
Skip to first unread message

Ed McDonagh

unread,
Nov 19, 2014, 6:58:17 AM11/19/14
to pyd...@googlegroups.com
Hello Darcy, pydicom community

I have a problem where in a DS tag (0018,7052 FilterThicknessMinimum, and 7053 Maximum), one vendor has populated it with two values using a comma to separate them. The idea is fine (two filters are in use, copper and aluminium each with a different thickness, but as the value representation is Decimal String commas are not allowed.

Therefore when pydicom attempts to getattr it fails with a ValueError.

Is there any way around this? What I'd like to do is have pydicom ignore the fact the value is not a float and allow me to get the string which I can then chop up and add to the database.

Is this possible?

I've logged an issue in OpenREM at https://bitbucket.org/openrem/openrem/issue/137

Kind regards

Ed

Author of OpenREM (http://openrem.org)




Ed McDonagh

unread,
Nov 20, 2014, 4:07:05 AM11/20/14
to pyd...@googlegroups.com
I've just though - I might be able to catch the ValueError containing the offensive value and process it from there. Thus not needing any change to pydicom :-)

I assume there isn't such a thing in pydicom as getattr_as_string or similar?

Thanks

Ed

Darcy Mason

unread,
Nov 20, 2014, 8:36:10 AM11/20/14
to pyd...@googlegroups.com
There was a similar kind of problem someone asked about once, as a comment on one of the wiki pages (https://code.google.com/p/pydicom/wiki/PydicomUserGuide).  See my comment Nov 8, 2012 (repeated below in case those comments are lost when pydicom moves to github). 
The trick is to access the raw data elements right after reading the file, before any conversion has been done.  Not elegant, but it should work.  In that comment, the solution was to change the VR.  In your case it might be better to change the value itself, by replacing comma with slash to turn the value into a multi-valued element and you would get it back as a list.

Here is my original comment answer  -------------:

ruudcools wrote: >> Is there a method to force pydicom to read a specific tag as a curtain data type. As example I have a tag which is defined in the dicom file as DS (Decimal String) however the value is "MU" a SH data type. The tag is the (x0300a,x000b3) tag.

Well, it's serious black magic, but you could change the VR while the read-in item is still a namedtuple "raw data element" (before conversion according to the VR). This requires a direct call to dict methods to bypass automatic conversions done by the Dataset class. It would look like this (here I've used VR of CS as that is actually the correct VR according to the dictionary):

ds = dicom.read_file("rtplan.dcm")
b0
= ds.BeamSequence[0]
d
= dict.__getitem__(b0, 0x300a00b3)
d2
= d._replace(VR='CS')
dict
.__setitem__(b0, 0x300a00b3, d2)
print b0.data_element('PrimaryDosimeterUnit')  # accessing the item causes conversion, but with new VR in place

Hope that helps. There might be a more elegant way, but that should work at least.

-----------

Darcy

Ed McDonagh

unread,
Nov 24, 2014, 4:57:55 PM11/24/14
to pyd...@googlegroups.com


On Thursday, 20 November 2014 13:36:10 UTC, Darcy Mason wrote:
There was a similar kind of problem someone asked about once, as a comment on one of the wiki pages (https://code.google.com/p/pydicom/wiki/PydicomUserGuide).  See my comment Nov 8, 2012 (repeated below in case those comments are lost when pydicom moves to github). 
The trick is to access the raw data elements right after reading the file, before any conversion has been done.  Not elegant, but it should work.  In that comment, the solution was to change the VR.  In your case it might be better to change the value itself, by replacing comma with slash to turn the value into a multi-valued element and you would get it back as a list.

 
Thanks Darcy. And congratulations on moving over to github - I find google code very difficult to navigate around, and aesthetically it is horrible!

Before your response I had come up with the solution of:
try:
    xray_filter_thickness_minimum = get_value_kw('FilterThicknessMinimum', dataset)
except ValueError as e:
    try:
        xray_filter_thickness_minimum = e.message.split(':')[1].strip().split(',')
    except:
        xray_filter_thickness_minimum = None


Which works, but has two issues - firstly it wouldn't cope if another vendor had used '\', and now I find that 'DeprecationWarning: BaseException.message has been deprecated as of Python 2.6'!

I think I'll go back to your method ;-) 

Ed McDonagh

unread,
Dec 21, 2016, 8:47:54 AM12/21/16
to pydicom
Hi Darcy, pydicom team.

A couple of years ago you showed me a fix for reading some poorly implemented DICOM that had a 'DS' field with a value that included two floats separated by a comma instead of a slash. I implemented your solution to replace the value element with a slash before reading it again and it has been working fine.

My problem now is to try and include testing this function in the tests. I am struggling to construct a dataset that includes the dodgy value!

Is it possible? Or must I find a dodgy source DICOM file and test against that?

What I have tried to do is this:
ds = Dataset()
import dicom
ds = dicom.dataset.Dataset()
ds.FilterThicknessMinimum = 1.23
d = dict.__getitem__(ds, 0x187052)
d2 = d._replace(value='0.34,1.23')

At which point I get the following error:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'DataElement' object has no attribute '_replace'

However, I can't see how this is different from what I am doing in reverse for the dodgy DICOM files.

Any ideas?



On Thursday, 20 November 2014 13:36:10 UTC, Darcy Mason wrote:

Ed McDonagh

unread,
Dec 21, 2016, 9:04:35 AM12/21/16
to pydicom
Just noticed I left a ds = Dataset() at the top of my example - just a mistake in constructing the example to copy and paste into the forum message.

Darcy Mason

unread,
Dec 21, 2016, 12:58:45 PM12/21/16
to pydicom
The ds.FilterThicknessMinimum assignment is created as a DataElement, but you need a RawDataElement,

I suggest you import RawDataElement from pydicom.dataelem, then add any you create to a dict, which is then passed to the constructor for Dataset.

Untested pseudo-code:
rawelem = RawDataElement(....)   # needs tag VR length value value_tell is_implicit_VR is_little_endian
rawdict
= {tag:rawelem}
ds
= Dataset(rawdict)


Give that a try and let us know,
Regards,
Darcy

Ed McDonagh

unread,
Dec 21, 2016, 2:35:22 PM12/21/16
to pydicom
Wonderful, thanks.

This seems to work well:
from dicom.dataelem import RawDataElement
from dicom.dataset import Dataset
from dicom.tag import Tag
rawelemmin = RawDataElement(Tag(0x187052), 'DS', 9, '0.09,1.18', 0, False, True)
rawelemmax = RawDataElement(Tag(0x187054), 'DS', 9, '0.11,1.22', 0, False, True)
rawdict = {0x187052: rawelemmin, 0x187054: rawelemmax}
ds = Dataset(rawdict)

However, the refactoring of the code I'm trying to test in order to test it has broken the function! I am at last making progress though, thanks!

Ed
Reply all
Reply to author
Forward
0 new messages