Deleting a Sequence

931 views
Skip to first unread message

Chris Horn

unread,
Jul 22, 2013, 12:07:45 AM7/22/13
to fo-d...@googlegroups.com
So Deleting a Sequence works well,
get a reference to the sequence then Dataset.Remove(seq) no problem

Private sequence's get mangled to a single tag that still can't be removed any suggestions?
The only example files I have are live customer Images so I'm unable to supply them, as processing the files also seems to mangle this sequence..

see the attached image. I just can't get a ref to this seqence

MedcomSeq.PNG

Chris Horn

unread,
Jul 22, 2013, 8:14:49 PM7/22/13
to fo-d...@googlegroups.com, colby....@gmail.com
Update, DicomDump can render the image and display the tag info
when I try to Dicom Send these files the DicomClient gives the following error

Dicom.DicomDataException: Unknown VR: '♦ '

Vladimir Tregub

unread,
Jul 23, 2013, 8:35:48 AM7/23/13
to fo-d...@googlegroups.com
Hi Chris,
 
What do you mean by "Private sequence's get mangled to a single tag "?
 
I have an SC DICOM file without private tags and I add a sequence and a tag as shown in that jpeg picture you attached to your post:
 
 
  DicomDataset ds = DicomFile.Open("smpte.dcm").Dataset;
  DicomDataset seqds = new DicomDataset();
  seqds.Add(new DicomTag(0x0029,0x0010, "SIEMENS MEDCOM HEADER"), "SIEMENS MEDCOM HEADER");
  seqds.Add(new DicomTag(0x0029,0x1041, "SIEMENS MEDCOM HEADER"), "SOM 5 TPOS");
  seqds.Add(new DicomTag(0x0029,0x1042, "SIEMENS MEDCOM HEADER"), "SOM 5 NULLPOSITION");
  seqds.Add(new DicomTag(0x0029,0x1043, "SIEMENS MEDCOM HEADER"), "VB10A 20030626");
  seqds.Add(new DicomTag(0x0029,0x1044, "SIEMENS MEDCOM HEADER"), 
            new byte[] {43,48,48,48,48,48,48,48,48,48,0,159});
  ds.Add(new DicomTag(0x0029,0x1140, "SIEMENS MEDCOM HEADER"), seqds);
  ds.Add(DicomTag.RequestedProcedureDescription, "CT ABDO/PELVIS");
  DicomFile dfnew = new DicomFile(ds);
  dfnew.Save("privateseq.dcm");

 
If I remove a private creator name from a line ds.Add(new DicomTag(0x0029,0x1140, "SIEMENS MEDCOM HEADER"), seqds), the compiled exe, quite naturally, will report "Unable to create DICOM element of type UN with values of type Dicom.DicomDataset" when executing. Compiled with the private creator name following the parameters (0x0029,0x1140) of a tag constructor, the executable produces a dicom file with dataset containing SIEMENS MEDCOM HEADER private creator tags. The file can be sent to PACS with
 
var client = new DicomClient();
var request = new DicomCStoreRequest(DicomFile.Open("privateseq.dcm"));
 
client.AddRequest(request);
client.Send(PACSIPaddress, PACSTCPport, false, AETitle, PACSAETitle);
 
The private sequence can be removed from the file with
 
  DicomDataset ds = DicomFile.Open("privateseq.dcm").Dataset;
  ds.Remove(new DicomTag(0x0029,0x1140));
  DicomFile dfnew = new DicomFile(ds);
  dfnew.Save("privateseqdeleted.dcm");
 
Here, you need not include a private creator parameter in the tag constructor [the line ds.Remove(new DicomTag(0x0029,0x1140));] in contrast to as we did it earlier with ds.Add. If you do, no exceptions will be reported during execution, but the sequence (0029,1140) will not be removed from a dataset.
 

Vladimir Tregub

unread,
Jul 23, 2013, 12:33:55 PM7/23/13
to fo-d...@googlegroups.com
I admit that my explanation at its end becomes somewhat confused.
 
May be I do not understand the library, but:
 
If we add private tags to an exisiting dataset and type out the dataset tags before filesaving op (iterating dataset without entering into sequence datasets, shallow iteration)
 
 
  DicomDataset ds = DicomFile.Open("smpte.dcm").Dataset;
 
  ds.Add(new DicomTag(0x0029,0x1041, "SIEMENS MEDCOM HEADER"), "some tag and dummy content for the nonce");
  DicomDataset seqds = new DicomDataset();
  seqds.Add(new DicomTag(0x0029,0x0010, "SIEMENS MEDCOM HEADER"), "SIEMENS MEDCOM HEADER");
  seqds.Add(new DicomTag(0x0029,0x1041, "SIEMENS MEDCOM HEADER"), "SOM 5 TPOS");
  ...
  ds.Add(new DicomTag(0x0029,0x1140, "SIEMENS MEDCOM HEADER"), seqds);
 
  foreach (DicomItem di in ds)
   Console.WriteLine(di.Tag);
  DicomFile dfnew = new DicomFile(ds);
  dfnew.Save("privateseq.dcm");

 
we'll see the private tags with private creators specified in the printout:
 
...
(0028,0103)
(0029,1041:SIEMENS MEDCOM HEADER)
(0029,1140:SIEMENS MEDCOM HEADER)
(0032,1060)
(7fe0,0010)
 
And then, if we read the saved privateseq.dcm from disk and type out the tags of the file dataset
 
  DicomDataset ds = DicomFile.Open("privateseq.dcm").Dataset;
 
  foreach (DicomItem di in ds)
   Console.WriteLine(di.Tag);
 
we will see the same tags, but the private creator specifiers are gone:
 
...
(0028,0103)
(0029,1041)
(0029,1140)
(0032,1060)
(7fe0,0010)
 
I expected that the tag's private creator is saved with the file dataset.
 

Chris Horn

unread,
Jul 24, 2013, 1:47:30 AM7/24/13
to fo-d...@googlegroups.com
Hi Vladimir,

2 problems discovered here simply trying to remove Tag .

ds.Remove(new DicomTag(0x0029,0x1140));

See attached image... it only removes the private creater...

also

var client = new DicomClient();
var request = new DicomCStoreRequest(DicomFile.Open("privateseq.dcm"));
 
client.AddRequest(request);
client.Send(PACSIPaddress, PACSTCPport, false, AETitle, PACSAETitle);

does work however


var client = new DicomClient();
var request = new DicomCStoreRequest(Dataset));

 
client.AddRequest(request);
client.Send(PACSIPaddress, PACSTCPport, false, AETitle, PACSAETitle);

it fails

so summing up the problems are this..

remove tag known or private works - no problem
removing a known sequence works like a champ - no problem
removing a private sequence - fails
CStore seems to fail when unknown tags exist in the dateset and
DicomCStoreRequest(Dataset) is used - fails
CStore request works as long as 
DicomCStoreRequest(DicomFile.Open("privateseq.dcm") or DicomCStoreRequest("privateseq.dcm")is used - no problem
Message has been deleted

Vladimir Tregub

unread,
Jul 24, 2013, 6:51:10 AM7/24/13
to fo-d...@googlegroups.com
Hi Chris,
 
Please let out my above explanations on the subject of private-tag sequence removal and see in PS 3.5-2011, Digital Imaging and Communications in Medicine (DICOM), Part 5: Data Structures and Encoding, pp. 45-46, section 7.8 PRIVATE DATA ELEMENTS:
 
' Private Creator Data Element (gggg,0010), is a Type 1 Data Element that identifies the
' implementor reserving element (gggg,1000-10FF), Private Creator Data Element (gggg,0011)
' identifies the implementor reserving elements (gggg,1100-11FF), and so on, until Private
' Creator Data Element (gggg,00FF) identifies the implementor reserving elements (gggg,FF00-
' FFFF).
 
So,
 
 
using System;
using System.Collections;
using Dicom;
using Dicom.IO;
namespace PrivateTagFileSetOperations
{
    class Program
    {
        [STAThread]
 static void Main(string[] args)
 {
     try
     {

  DicomDataset ds = DicomFile.Open("smpte.dcm").Dataset;
  ds.Add(new DicomTag(0x0029,0x0011, "SIEMENS MEDCOM HEADER"), "SIEMENS MEDCOM HEADER");
  ds.Add(new DicomTag(0x0029,0x1141, "SIEMENS MEDCOM HEADER"), "tag to test");
  DicomDataset seqds = new DicomDataset();
  seqds.Add(new DicomTag(0x0029,0x0010, "SIEMENS MEDCOM HEADER"), "SIEMENS MEDCOM HEADER");
  seqds.Add(new DicomTag(0x0029,0x1041, "SIEMENS MEDCOM HEADER"), "SOM 5 TPOS");
  seqds.Add(new DicomTag(0x0029,0x1042, "SIEMENS MEDCOM HEADER"), "SOM 5 NULLPOSITION");
  seqds.Add(new DicomTag(0x0029,0x1043, "SIEMENS MEDCOM HEADER"), "VB10A 20030626");
  seqds.Add(new DicomTag(0x0029,0x1044, "SIEMENS MEDCOM HEADER"),
   new byte[] {43,48,48,48,48,48,48,48,48,48,0,159});
  ds.Add(new DicomTag(0x0029,0x1140, "SIEMENS MEDCOM HEADER"), seqds);
  ds.Add(DicomTag.RequestedProcedureDescription, "CT ABDO/PELVIS");
  foreach (DicomItem di in ds)
   Console.WriteLine(di.Tag);
  DicomFile dfnew = new DicomFile(ds);
  dfnew.Save("privateseq.dcm");
     }
     catch (Exception e) { Console.WriteLine(e.Message); }
 }
    }
}
 
creates a file-set privateseq.dcm that contains Siemens Medcom Header private tags. Please notice that the created dataset contains a tag (0029,0011:SIEMENS MEDCOM HEADER).
 
The code below removes a private-tag sequence from this dataset:
 

using System;
using System.Collections;
using Dicom;
using Dicom.IO;
namespace PrivateTagFileSetOperations
{
    class Program
    {
        [STAThread]
 static void Main(string[] args)
 {
     try
     {

  DicomDataset ds = DicomFile.Open("privateseq.dcm").Dataset;
  foreach (DicomItem di in ds)
   Console.WriteLine(di.Tag);
  ds.Remove(new DicomTag(0x0029,0x1140, "SIEMENS MEDCOM HEADER"));
  DicomFile dfnew = new DicomFile(ds);
  dfnew.Save("privateseqdeleted.dcm");
     }
     catch (Exception e) { Console.WriteLine(e.Message); }
 }
    }
}
 
QED.

Chris Horn

unread,
Jul 24, 2013, 9:12:27 AM7/24/13
to fo-d...@googlegroups.com
you seem to be be missing the point that the sequence is NOT it fails and the catch block is hit ! google it its a problem that is wide spread with this tag and older viewers.

The problem is I have 3 different products that all have diferent results

as I point out in my last post if you try and send by passing in a dataset to the c Storerequest example it crashes fo-Dicom 100 % repeatable

if you pass a dicom file or the path to the dicom image to the  CStore request I can transmit it.

so there must be a difference in that way the the data set is parsed loading from DicomFile vs passing an in memory DataSet.

Also as mentioned trying to remove this sequence fails... I'm reluctant to upload my sample image as they contain patient data.

I have tried both the methods you have advised before posting this problem both fail
ds.Remove(new DicomTag(0x0029,0x1140));
- fails
ds.Remove(new DicomTag(0x0029,0x1140, "SIEMENS MEDCOM HEADER")); - fails

this was shown in the post that was deleted by someone


Chris Horn

unread,
Jul 24, 2013, 9:27:12 AM7/24/13
to fo-d...@googlegroups.com
Just to make sure I've copy and pasted your code into my test project and have the same results
the ds.remove does not remove anything..... open the original and the newly created file and the sequence is still there.

it has me confused, pick any non-private sequence and ds.remove get rid of it no problem..

Vladimir Tregub

unread,
Jul 24, 2013, 11:15:23 AM7/24/13
to fo-d...@googlegroups.com
Hi Chris,
 
I did not understand from your posts: you failed to remove private-tag seqs from only your original Siemens file (which I've never seen except for a bit of its dump picture), or also from a file privateseq.dcm produced with my createprivateseq.exe utility?
 
if you like, you can reproduce EXACTLY my tests in your computing environment. If we arrive at different outcomes of an identical test procedure, it may be of interest to the fo dicom developers.
 
So,
 
First: you can compile my codes outside your project and even outside VS:
 
>set path C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319
>csc createprivateseq.cs /reference:Dicom.dll
>createprivateseq.exe
>csc delprivateseq.cs /reference:Dicom.dll
>delprivateseq,exe
 
Second: you'll view the produced privateseq.dcm and privateseqdeleted.dcm with the Dicom.Dump.exe of the fo dicom binary distribution.
 
Third: you try and send 'privateseq.dcm' to the C-Store server of Dicom.CStoreSCP.exe with
 
DicomClient = new DicomClient();
client.AddRequest(new DicomCStoreRequest(DicomFile.Open("privateseq.dcm")));

client.Send(PACSIPaddress, PACSTCPport, false, AETitle, PACSAETitle);
 
You need also have a fo dicom v1.0.35 compiled library file Dicom.dll from the distribution binaries, fo-dicom_1.0.35.zip (I did it successfully with v1.0.33, too) and an SC or OT DICOM image file without private tags (to be enriched with private tags in the process) in your working directory. You can take this source DICOM image file elsewhere, for ex., from imgdisplay_testcases.zip, http://ihedoc.wustl.edu/mesasoftware/12.x/display_consistency/index.html or I can elaborate on createprivateseq.cs to make it able to produce a target "private-tag-rich" DICOM file from the scratch, w/o a source DICOM image file.
 
If you like, I'll pack and send you my source files, compiled executables, and DICOM image files.
 

Chris Horn

unread,
Jul 24, 2013, 6:27:08 PM7/24/13
to fo-d...@googlegroups.com
Hi Vladimir,

This I'll try to anonymize one of the of the images and upload it for others to test with. I'm using the v1.0.35 fo Dicom

so far you may have missed some the points I've raised.

1. I don't need to create an image with this private tag I have a 3000 image CT study with these and other private tags and sequences.

2. My project and you sample code to remove the sequence fail to remove the sequence (not looking at the sample to build a dataset).
    My code and your work perfectly with every other public tag and sequence have tried.

3. DicomCStoreReuest has 3 constructors 2 work and one fails (with these particular images).
    until this new CT came online at a customers site I was able to use the 1st constructor (passing in only a dataset),
    for these images I need to use the 2nd or 3rd constructor call. I can live with that, I'll get around to looking into why its failing at some point,
    If other know perhaps some one will resolve this issue before me.

maybe you can have a look at the tag striping once I upload an anonymize image.

Thanks for you feed back so far Vladimir

Vladimir Tregub

unread,
Jul 24, 2013, 9:32:51 PM7/24/13
to fo-d...@googlegroups.com
I dont miss your points, but I try to resolve your problems "sequentially", in the order of their arrival.
 
You dont need to create an image with private tags, but I was obliged to construct a sample file, because the tag removal operation cannot be applied to a piece of graphical image that you supplied with your first post.
 
The code of the line
 
  ds.Remove(new DicomTag(0x0029,0x1140, "SIEMENS MEDCOM HEADER"));
from my program, built with the fo dicom library, (and from any other program of this kind) perfectly well SUCCEEDS in removal of a PRIVATE tag from the sample file containing the tags seen in the picture of dicom dump of your first post. Why do you fail to do the similar operation with your file, is an open question. It may be answered by the other programmer (for example, by me) on the condition that we have the appropriate data at hand, that is, your code and your image files that your code fails to operate on. Maybe only one of these two (either your program or your file) will be sufficient to pinpoint your problem, but some details from you are necessary for an analysis, aren't they?
 
Успехов в борьбе с "приватными" тэгами,
 
Владимир.
 

Chris Horn

unread,
Jul 25, 2013, 3:39:16 AM7/25/13
to fo-d...@googlegroups.com
Thanks Vladimir,

As soon as I've anonymized some images I'll upload them for others to test with.

One thing I can tell you for certain after many years of doing this is every Dicom toolkit I've used has a few issues with Siemens Images, results vary

So I'll be extremity happy if some one can help pin point the problem and how to work around it

Mahesh Dubey

unread,
Jul 25, 2013, 6:16:25 AM7/25/13
to fo-d...@googlegroups.com
Hello;
       
 public void RemoveTag(DicomDataset dataset, DicomTag tag)
       
{
           
if (tag.IsPrivate)
           
{
               
var privateTag = dataset.GetPrivateTag(tag);
               
var creator = new DicomTag(privateTag.Group, 0x0010);
                dataset
.Remove(privateTag);
                dataset
.Remove(creator);//Remove creator also.
           
}
           
else
           
{
                dataset
.Remove(tag);
           
}
       
}

HTH
Mahesh

Vladimir Tregub

unread,
Jul 25, 2013, 8:50:45 PM7/25/13
to fo-d...@googlegroups.com
Hi Mahesh,
 
Your method RemoveTag is quite useless, because you hardcoded 0x0010 for the Private Creator Data element. While the Private Creator Data element 0x0010 can be found in many instances of DICOM datasets, there are instances with the Private Creator Data elements in the entire range of 0x0010 - 0x00FF, reserved by the DICOM standard for the Private Creator Data elements. So, one way or the other, you should know the private creator name beforehand to operate on a private creator tag, and the single line in the user code
 
ds.Remove(new DicomTag(privategroup, element, privateCreatorName));
 
will do the job.
 
Besides, it is not necessary and often erroneously to remove the private creator data element, when you remove a single private creator tag.
 
---

Vladimir Tregub

unread,
Jul 26, 2013, 4:30:46 AM7/26/13
to fo-d...@googlegroups.com
Chris,
 
I could not find a sample Siemens DICOM file with a private-tag sequence, but I found a Philips DICOM file to research into the problem you possibly encountered when removing a private sequence. I am almost sure that my finding can be applied to private-sequence rich DICOM files of any manufacturer.
 
To start with, the file b0.dcm (taken from https://github.com/nicholsn/Philips-Multiframe-DICOM/archive/master.zip and attached here) cannot be open with Dicom.Dump.exe v.1.0.35 (notorious 'Requested xxxxxxx bytes past end of file'), but Dicom.Dump.exe v.1.0.33 successfully opens it.
 
The 'best answer' to the June 27 forum post 'Requested xxxx bytes past end of file' states that the reason is an improper processing by the library of "offending" tags, and healed it by modifying a DicomReader.cs source file. Later I will look closer to it, but it seems that the remedy aggravated the patient condition and for now I replaced the DicomReader.cs of version 1.0.35 with the DicomReader.cs of version 1.0.33 and recompiled the v 1.0.35 library.
 
Simply replacing the Dicom.dll with the recompiled file in the folder of fo-dicom binaries, I can open b0.dcm with Dicom.Dump.exe without any exception thrown.
 
You can use the following utility, also with the recompiled Dicom.dll in the working directory, to remove a private-tag sequence from your files:
 
 
using System;
using System.IO;
using Dicom;
using Dicom.IO;
namespace PrivateTagFileSetOperations
{
    class Program
    {
        [STAThread]
 static void Main(string[] args)
 {
     if (args.Length<1) { Console.WriteLine("usage: delprivatetag dicomfilepath"); return; }
     if (!File.Exists(args[0].ToString())) { Console.WriteLine("No such file"); return; }
     string filename = Path.GetFullPath(args[0].ToString());
     Console.WriteLine("Enter tag, either standard or private, to remove");
     Console.WriteLine(" (like \"gggg,eeee\" or other parseable string):");
     string strTag = Console.ReadLine();
     try
     {
  DicomTag tagToRemove = DicomTag.Parse(strTag);
  DicomDataset ds = DicomFile.Open(args[0].ToString()).Dataset;
  ushort group = tagToRemove.Group;
  ushort element = tagToRemove.Element;
  int privatecreatorelement = (element & 0xFF00) >> 8;
  string privatecreator = ds.Get<string>(new DicomTag(group, (ushort) privatecreatorelement));
  foreach (DicomItem di in ds)
  {
      if (di.Tag.Group==group)
   Console.WriteLine(di.Tag);
  }
  Console.WriteLine("///");
  try
  {
      ds.Remove(new DicomTag(group, element, privatecreator));
  }
  catch
  {
      Console.WriteLine("No {0} tag in dataset.", strTag);

  }
  foreach (DicomItem di in ds)
  {
      if (di.Tag.Group==group)
   Console.WriteLine(di.Tag);
  }
  Console.WriteLine("Press any key to continue..."); Console.ReadLine();
  (new DicomFile(ds)).Save(String.Concat("PrivateElementRemoved-", args[0].ToString()));
     }
     catch (Exception e) { Console.WriteLine(e.Message); Console.ReadLine();}
 }
    }
}
 
I has attached the executable of this utility and also attached re-compiled Dicom.dll ver 1.0.35 (DicomReader.cs reversed to ver 1.0.33).
 
To enter a private tag name that you want to be removed with this utility, you need not specify a private tag creator. For example, 2005,1402 or simply 20051402 will do. The utility type out the the dataset group the removed element belongs to, before and after the remove operation, and saves the dataset in the new file. The utility can be started from the command line or by dragging a DICOM file and dropping it on a removeprivatetag.exe executable.
 
 
b0.dcm
Dicom.dl_
removeprivatetag.ex_

Vladimir Tregub

unread,
Jul 26, 2013, 5:20:07 AM7/26/13
to fo-d...@googlegroups.com
Addendum:
 
to make a drag-and-drop usage of removeprivatetag.exe more convenient, the filesave method parameter must be written as follows:
 
(new DicomFile(ds)).Save(String.Concat(Path.GetFullPath(args[0].ToString()), ".edited.dcm"));
removeprivatetag.ex_

Mahesh Dubey

unread,
Jul 26, 2013, 7:19:34 AM7/26/13
to fo-d...@googlegroups.com
Hi Vladimir ;
       The code which I had posted is just to exhibit the private tag deletion. Whenever we delete private tag we have to consider its creator
 also. It  doesn't make any sense if we are deleting all the private tag of a particular implementer and not deleting its PrivateCreator tag.
So one extra check can be added to my code before deleting creator, i.e. to check whether any tag from a particular creator is present 
in the dataset or not, if not then delete the  creator also. 

You can get all the tag from private creator using the 
DicomDictionary.Default[tag.PrivateCreator].Select(o => o.Tag)

 Mahesh


  

Reply all
Reply to author
Forward
0 new messages