Thursday, May 17, 2012
Google Custom Search

ClearCanvas Highlights

Download our Open Source software
Watch some Videos
Get the Source
Check out our Licensing
Join our  Forums
Some Research: OICR IPP-Trials

Our Community

Membership Membership:
Latest New User Latest: JBauza
New Today New Today: 19
New Yesterday New Yesterday: 33
User Count Overall: 22559

People Online People Online:
Visitors Visitors: 9
Members Members: 1
Total Total: 10

Online Now Online Now:
01: JBauza

ClearCanvas Community Forums

Private tags and interpreting UN attributes
Last Post 2011-09-06 07:31 PM by chafey. 21 Replies.
Printer Friendly
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Page 1 of 212 > >>
Author Messages
jasper.yeh
Senior Member
Senior Member
Posts:523
Avatar

--
2008-06-18 11:14 AM  
Our code reads/writes private tags, and since these tags aren't defined in the data dictionary, they're read in as UN tags in the dataset when using implicit.

So far, my thoughts are to get the UN attribute from the attributecollection using the private DicomTag, get the values from the UN attribute as a byte[], create a Dicom.IO.ByteBuffer with this byte array and set all parameters for interpreting data (endianess and the like), use the ToXYZ methods to assign data to the values of a new XY attribute, and then set the item in attributecollection at the private tag to this new XY attribute.

And then, somewhere in there, put a huge switch on the actual VR and cover all possible cases of XY.

Any comments on this method? Or perhaps is there an easier way?


// Jasper
steve
Senior Member
Senior Member
Posts:1932

--
2008-06-18 12:24 PM  
Hi Jasper,

The method you suggest for solving this problem would work. However, I'd probably actually recommend that instead you develop a way to include private tags in the data dictionary. Specifically, if you were to implement this ticket:

https://trac.clearcanvas.ca/source/ticket/937


I would suggest creating a new class, DicomPrivateTagDictionary, which could include the dictionary for private tags, and the ability to look up the tag based on the Private Creator Code, group, and element byte. You would then require a small change in the StreamReader.cs, in the Read method, where we current call DicomTagDictionary.GetDicomTag(), to do a check to see if the tag is a private attribute, and call the DicomPrivateTagDictionary instead. (you'd also have to retrieve the private creator code out of the message at this point.)

To start with, the DicomPrivateTagDictionary could just be loaded at run-time with your private tags whenever your app is initialized. Let me know if you have questions. If you know your private tags are pretty static, I wouldn't mind having the DicomPrivateTagDictionary having a list of "known" private tags for which the definition is publicly available. You could just include your tags when the class is init right in the tool kit code.

Steve


Real-time support available to Clinical Edition and Team Edition customers
dblanchard
Senior Member
Senior Member
Posts:185

--
2008-06-18 01:32 PM  
Hi,

I was actually thinking about implementing a Private Tag Dictionary because we actually write as ExplicitVR to get the UN issue.

I think it would be helpful to have a List of Private Dictionaries because we may have several for different companies.   ie, make a IDictionary or IPrivateDictionary interface w/ the appropriate methods to get DicomTag info that each private dictionary concrete class can implement.  (The DicomTagDictionary could do the same)

Regards,

Dan



jasper.yeh
Senior Member
Senior Member
Posts:523
Avatar

--
2008-06-18 05:13 PM  
Well, I had actually started writing something of the sort already. I'll post my solution when I've cleaned it up a bit. Basically, I have an implementor class that defines all the private tags and can create a collection of dicomattributes that wraps an actual dicomattributecollection so that subsequent modifications to either collection are reflected in the other.

On a side note: I had a couple of problems with properly decoding some UN attributes that should be a binary type. The Dicom.IO.ByteConvertor has methods ToUInt16Array and ToInt16Array but, unlike the other ToXYZArray methods, do not seem to take into account system byte order. Additionally, ToDoubleArray has a typo in it, causing it to decode a multi-valued FD attribute using the lower dword of one double and the upper dword of the next double.

Attachment: ByteConvertor.cs.patch

// Jasper
steve
Senior Member
Senior Member
Posts:1932

--
2008-06-18 07:09 PM  
Dan,

Concerning your comments, are you saying you have conflicts with the tags between different companies that you can't just include all the private tags in a single dictionary? It seems like the combination of the private creator code, the group number, and the element byte should be a unique identifier of a private tag. Because of this, I'm unsure of the need for separate dictionaries. I guess there would, however, be some value in having a dedicated interface for the dictionary for loading purposes at run time.

Jasper -- concerning the patch, thanks for posting. I think we need some slightly better regression tests in this case to check for streaming. It looks like we must not have been testing streaming in out messages for all VRs, and missed this problem. I'll take a closer look at it and your patch.

Thanks,
Steve


Real-time support available to Clinical Edition and Team Edition customers
dblanchard
Senior Member
Senior Member
Posts:185

--
2008-06-18 10:54 PM  
Hi Steve,

Perhaps it is not necessary to be able to have several private dictionaries, but it could be helpful to have a different private dictionary for each vender, not because of tag conflict but just for code organizational purposes.  But I could live without it...  or, are you just proposing having a way to add tags at runtime that the stream reader and writer will be able to read?  I could live with that too...

Dan



steve
Senior Member
Senior Member
Posts:1932

--
2008-06-19 12:19 AM  
Dan & Jasper,

Upon further review and looking at the DicomTag class, it looks like there's some changes that would need to be done to support this. Specifically, we don't have a way to store the "Private Creator Code" in the DicomTag object. The group and element byte could just be encoded in the tag value itself. There needs to be a new constructor added to DicomTag to be used when defining a private tag.

Concerning the dictionary, i was thinking of something like this:

public static class DicomPrivateTagDictionary
{
static DicomTagDictionary();

public static IList GetDicomPrivateTagList()

public static DicomTag GetDicomPrivateTag(string creatorCode, ushort group, byte elementByte)

public static void AddPrivateTag(DicomTag tag)

public static void AddPrivateTagList(IEnumerable list)
}

At init time, you would add the private tags individually or as a list.

Steve


Real-time support available to Clinical Edition and Team Edition customers
dblanchard
Senior Member
Senior Member
Posts:185

--
2008-06-19 11:16 AM  
Steve,

I think we would need a few other methods to retrieve private tags, or would this be available via methods in the standard dictionary?  ie,

public static DicomTag GetDicomTag(uint tag, bool checkDicomStandardTags);
public static DicomTag GetDicomTag(string name, bool checkDicomStandardTags);

note, the checkDicomStandardTags param may not be necessary, I just had it my private dictionary for convenience.

Regards,

Dan



jasper.yeh
Senior Member
Senior Member
Posts:523
Avatar

--
2008-06-19 02:12 PM  

Hi Guys,

Attached is my solution for supporting private tags in my application, abstracted to be extensible for general purposes.

The abstract class DicomPrivateTag is extended to define private tags using only a byte. The abstract class DicomPrivateImplementor is extended to define the creator code, the private group, and the list of DicomPrivateTags alllowed. To access private tags in a dataset, the GetPrivateAttributes method of an instance of the implementor is called, passing in the source dataset. The return value is a DicomPrivateAttributeCollection, which is similar to DicomAttributeCollection except it is indexed on DicomPrivateTags. The private collection is only a wrapper, so changes in either collection are reflected in the other.

There is sample code in the included help files.

What do you think?

Edit 2011-08-04: Removed attachment because I no longer hold rights to distribute and relicense it.



// Jasper
echan
Basic Member
Basic Member
Posts:28

--
2008-08-12 04:13 PM  

Hi Steve,

I also need to handle private tags.
At the point where the reader encounters the private tag for creator code, how do I extract the creator code from the message?

Thanks in advance,

Eleanor



steve
Senior Member
Senior Member
Posts:1932

--
2008-08-12 04:37 PM  
Eleanor,

With the current implementation, the best way to access private tags in a message would be to use the iterator associated with the DicomAttributeCollection to step through all the tags in the message until you find the private creator code you are looking for. From that you should be able to navigate to the actual private tags you're looking for...

Steve


Real-time support available to Clinical Edition and Team Edition customers
jasper.yeh
Senior Member
Senior Member
Posts:523
Avatar

--
2008-08-12 04:55 PM  
Hi Eleanor,

If you just need to read the data in a private tag creator code attribute, then just access the dataset like with any other tag and then call a GetString(0, "") or ToString() on the attribute.

So, something like this:
DicomFile dcf = ...;
string creatorCode = dcf.DataSet[(uint)0x07570010].GetString(0, ""); //0x07570010 is the creator code tag


// Jasper
echan
Basic Member
Basic Member
Posts:28

--
2008-08-12 05:43 PM  

Actually, I'm following Steve's recommendation in the second reply and trying to make changes in StreamReader.

I can get it from the DicomAttributeCollection now.

Thanks,

Eleanor



dblanchard
Senior Member
Senior Member
Posts:185

--
2008-08-12 09:50 PM  
Hi

You are welcome to use my private dictionary as a sample.  See attached file.

Here is an example how to use it:

// this sets my PatientUid private tag in the dicom file's dataset
dicomFile.DataSet[PrivateDictionary.GetPrivateDicomTag(PrivateTag.PatientUid)].
SetStringValue(myPatientUid);

I also have a helper function to get either my private tag or the standard dicom tag:

GetDicomTag(uint tag, bool checkDicomStandardTags);

hope this helps.

dan


Attachment: PrivateDictionary.cs

echan
Basic Member
Basic Member
Posts:28

--
2008-08-13 10:30 AM  

Thanks Dan for the code sample.

Eleanor



awei
New Member
New Member
Posts:2

--
2011-03-21 01:00 PM  
Hi All,

Now is 2011. Do we have any new easy solution to create private tags?

Thanks.

Anthony


mtl
Basic Member
Basic Member
Posts:21

--
2011-03-21 02:44 PM  

Anthony,

I haven't yet had a need to create new private tags, but have been successful reading private tag data from Signa MR images using the RadFiler.Dicom.PrivateTags code posted by Jasper earlier in this discussion thread.  I expect it shouldn't be too difficult to write private tags instead of reading them.

-Matt



awei
New Member
New Member
Posts:2

--
2011-03-21 09:23 PM  
Hi Matt,

Thanks for your response.

Actually I want to add some private tags into a DicomFile instance and those tags need to be saved after DicomFile.Save(). I had "Invalid tag: xxxx" problem when using DicomFile.DataSet[privateTag].SetInt16(), because the private tag does not exist in DicomTagDictionary.

I have figured out how to add a private tag. It is just 4 lines code:
DicomTag tag = new DicomTag(privateTag, ..);
DicomAttribute dicomAttribute = tag.CreateDicomAttribute();
dicomFile.DataSet[privateTag] = dicomAttribute.Copy();
dicomFile.DataSet[privateTag].SetInt16();

-Anthony



mtl
Basic Member
Basic Member
Posts:21

--
2011-08-03 04:04 PM  

Jasper,

Is the code included in your RadFiler.Dicom.PrivateTags zip archive file provided for use and redistribution under the ClearCanvas license and/or the Open Software License v3.0 as described in http://www.clearcanvas.ca/dnn/About...fault.aspx?  (I presume that was likely your intent, but I'd like to explicitly receive your permission before redistributing your work.)

-Matt



jasper.yeh
Senior Member
Senior Member
Posts:523
Avatar

--
2011-08-04 05:45 PM  
Hi Matt,

Sorry, I actually had to remove that code now. It was written before I joined ClearCanvas, and its ownership remains with my employer at the time. I conferred with the current rights holder, who declined to authorize any further use of the code.

It was the intent at the time that the code be integrated into the framework as a third party contribution, and thus become available under the ClearCanvas license (and the subsequent OSLv3 license). However, that did not happen and now the rights holder has clarified the licensing terms.

Aside: I probably wouldn't design a generic private tag mechanism like that anymore, because it requires you to subclass too many things, resulting in a bunch of new DicomPrivateAttributeCollection instances that duplicate normal DicomAttributeCollection. A better design would be for you as the private tag creator to create a specialized lightweight wrapper for a DicomAttributeCollection with properties of the appropriate types, and the wrapper would handle creating the DicomTag objects and actually reading and writing to the dataset. This is how the current IOD implementations work (see the Iod/Modules folder in the DICOM project) - they're all just wrappers that provide a specialized view onto the dataset. You wouldn't have any duplicated functionality anywhere - simply create a new wrapper when needed.

Hope this helps,


// Jasper
You are not authorized to post a reply.
Page 1 of 212 > >>


Active Forums 4.1
Copyright 2012 ClearCanvas Inc.