File: gdcmDirectoryHelper.cxx

package info (click to toggle)
gdcm 2.4.4-3%2Bdeb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 32,912 kB
  • ctags: 52,166
  • sloc: cpp: 188,527; ansic: 124,526; xml: 41,799; sh: 7,162; python: 3,667; cs: 2,128; java: 1,344; lex: 1,290; tcl: 677; php: 128; makefile: 116
file content (267 lines) | stat: -rw-r--r-- 10,396 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

#include "gdcmDirectoryHelper.h"
#include "gdcmScanner.h"
#include "gdcmIPPSorter.h"
#include "gdcmAttribute.h"
#include "gdcmDataElement.h"
#include "gdcmReader.h"


namespace gdcm{
//given an SOPClassUID, get the number of series that are that SOP Class
//that is, the MR images, the CT Images, whatever.  Just have to be sure to give the proper
//SOP Class UID.
//returns an empty vector if nothing's there or if something goes wrong.
Directory::FilenamesType DirectoryHelper::GetSeriesUIDsBySOPClassUID(const std::string& inDirectory,
                                                                       const std::string& inSOPClassUID)
{
  Scanner theScanner;
  Directory theDir;
  theScanner.AddTag(Tag(0x0008, 0x0016));//SOP Class UID
  theScanner.AddTag(Tag(0x0020, 0x000e));//Series UID
  Directory::FilenamesType theReturn;

  try {
    theDir.Load(inDirectory);
    theScanner.Scan(theDir.GetFilenames());

    //now find all series UIDs
    Directory::FilenamesType theSeriesValues = theScanner.GetOrderedValues(Tag(0x0020,0x000e));

    //now count the number of series that are of that given SOPClassUID
    size_t theNumSeries = theSeriesValues.size();
    for (size_t i = 0; i < theNumSeries; i++){
      std::string theFirstFilename =
      theScanner.GetFilenameFromTagToValue(Tag(0x0020,0x000e), theSeriesValues[i].c_str());
      std::string theSOPClassUID = theScanner.GetValue(theFirstFilename.c_str(), Tag(0x0008,0x0016));
      //dicom strings sometimes have trailing spaces; make sure to avoid those
      size_t endpos = theSOPClassUID.find_last_not_of(" "); // Find the first character position from reverse af
      if( std::string::npos != endpos )
        theSOPClassUID = theSOPClassUID.substr( 0, endpos+1 );
      if (theSOPClassUID == inSOPClassUID.c_str()){
        theReturn.push_back(theSeriesValues[i]);
      }
    }
    return theReturn;
  } catch (...){
    Directory::FilenamesType theBlank;
    return theBlank;//something broke during scanning
  }
}


//given the name of a directory, return the list of CT Image UIDs
Directory::FilenamesType DirectoryHelper::GetCTImageSeriesUIDs(const std::string& inDirectory)
{
  return GetSeriesUIDsBySOPClassUID(inDirectory, "1.2.840.10008.5.1.4.1.1.2");
}

//given the name of a directory, return the list of CT Image UIDs
Directory::FilenamesType DirectoryHelper::GetMRImageSeriesUIDs(const std::string& inDirectory)
{
  return GetSeriesUIDsBySOPClassUID(inDirectory, "1.2.840.10008.5.1.4.1.1.4");
}

//given the name of a directory, return the list of CT Image UIDs
Directory::FilenamesType DirectoryHelper::GetRTStructSeriesUIDs(const std::string& inDirectory)
{
  return GetSeriesUIDsBySOPClassUID(inDirectory, "1.2.840.10008.5.1.4.1.1.481.3");
}

//given a directory and a series UID, provide all filenames with that series UID.
Directory::FilenamesType DirectoryHelper::GetFilenamesFromSeriesUIDs(const std::string& inDirectory,
                                                                     const std::string& inSeriesUID)
{
  Scanner theScanner;
  Directory theDir;
  theScanner.AddTag(Tag(0x0020, 0x000e));//Series UID
  Directory::FilenamesType theReturn;

  try {
    theDir.Load(inDirectory);
    theScanner.Scan(theDir.GetFilenames());
    //now find all series UIDs
    Directory::FilenamesType theSeriesValues = theScanner.GetOrderedValues(Tag(0x0020,0x000e));
    //now count the number of series that are of that given SOPClassUID
    size_t theNumSeries = theSeriesValues.size();
    for (size_t i = 0; i < theNumSeries; i++)
      {
      std::string theSeriesUID = theSeriesValues[i];
      //dicom strings sometimes have trailing spaces; make sure to avoid those
      size_t endpos = theSeriesUID.find_last_not_of(" "); // Find the first character position from reverse af
      if( std::string::npos != endpos )
        theSeriesUID = theSeriesUID.substr( 0, endpos+1 );
      if (inSeriesUID == theSeriesUID)
      {
	    Directory::FilenamesType theFilenames =
		    theScanner.GetAllFilenamesFromTagToValue(Tag(0x0020, 0x000e), theSeriesValues[i].c_str());
		  Directory::FilenamesType::const_iterator citor;
		  for (citor = theFilenames.begin(); citor < theFilenames.end(); citor++)
        {
		    theReturn.push_back(*citor);
		    }
    //      theReturn.push_back(theScanner.GetFilenameFromTagToValue(Tag(0x0020,0x000e),
    //        theSeriesValues[i].c_str()));
      }
    }
    return theReturn;
  } catch (...){
    Directory::FilenamesType theBlank;
    return theBlank;//something broke during scanning
  }

}
//the code in GetSeriesUIDsBySOPClassUID will enumerate the CT images in a directory
//This code will retrieve an image by its Series UID.
//this code doesn't return pointers or smart pointers because it's intended to
//be easily wrapped by calling languages that don't know pointers (ie, Java)
//this function is a proof of concept
//for it to really work, it needs to also
std::vector<DataSet> DirectoryHelper::LoadImageFromFiles(const std::string& inDirectory,
                                                           const std::string& inSeriesUID)
{
  Scanner theScanner;
  Directory theDir;
  theScanner.AddTag(Tag(0x0020, 0x000e));//Series UID
  std::vector<DataSet> theReturn;
  std::vector<DataSet> blank;//returned in case of an error

  try {
    theDir.Load(inDirectory);
    theScanner.Scan(theDir.GetFilenames());

    //now find all series UIDs
    Directory::FilenamesType theSeriesValues = theScanner.GetOrderedValues(Tag(0x0020,0x000e));

    //now count the number of series that are of that given SOPClassUID
    size_t theNumSeries = theSeriesValues.size();
    for (size_t i = 0; i < theNumSeries; i++){
      if (inSeriesUID == theSeriesValues[i]){
        //find all files that have that series UID, and then load them via
        //the vtkImageReader
        Directory::FilenamesType theFiles =
        theScanner.GetAllFilenamesFromTagToValue(Tag(0x0020, 0x000e), theSeriesValues[i].c_str());
        IPPSorter sorter;
        sorter.SetComputeZSpacing(true);
        sorter.SetZSpacingTolerance(0.000001);
        if (!sorter.Sort(theFiles)){
          gdcmWarningMacro("Unable to sort Image Files.");
          return blank;
        }
        Directory::FilenamesType theSortedFiles = sorter.GetFilenames();
        for (unsigned long j = 0; j < theSortedFiles.size(); ++j){
          Reader theReader;
          theReader.SetFileName(theSortedFiles[j].c_str());
          theReader.Read();
          theReturn.push_back(theReader.GetFile().GetDataSet());
        }
        return theReturn;
      }
    }
    return blank;
  } catch (...){
    gdcmWarningMacro("Something went wrong reading CT images.");
    return blank;
  }
}


//When writing RTStructs, each contour will have z position defined.
//use that z position to determine the SOPInstanceUID for that plane.
std::string DirectoryHelper::RetrieveSOPInstanceUIDFromZPosition(double inZPos,
                                                const std::vector<DataSet>& inDS)
{
  std::vector<DataSet>::const_iterator itor;
  Tag thePosition(0x0020, 0x0032);
  Tag theSOPInstanceUID(0x0008, 0x0018);
  std::string blank;//return only if there's a problem
  for (itor = inDS.begin(); itor != inDS.end(); itor++)
    {
    if (itor->FindDataElement(thePosition))
      {
      DataElement de = itor->GetDataElement(thePosition);
      Attribute<0x0020,0x0032> at;
      at.SetFromDataElement( de );
      if (fabs(at.GetValue(2) - inZPos)<0.01)
        {
        DataElement de2 = itor->GetDataElement(theSOPInstanceUID);
        const ByteValue* theVal = de2.GetByteValue();
        size_t theValLen = theVal->GetLength();
        std::string theReturn(de2.GetByteValue()->GetPointer(), theValLen);
        return theReturn;
        }
      }
    }
  return blank;
}

//When writing RTStructs, the frame of reference is done by planes to start with
std::string DirectoryHelper::RetrieveSOPInstanceUIDFromIndex(int inIndex,
                                                               const std::vector<DataSet>& inDS)
{

  Tag theSOPInstanceUID(0x0008, 0x0018);
  std::string blank;//return only if there's a problem
  if (inDS[inIndex].FindDataElement(theSOPInstanceUID)){
    DataElement de = inDS[inIndex].GetDataElement(theSOPInstanceUID);
    const ByteValue* theVal = de.GetByteValue();
    size_t theValLen = theVal->GetLength();
    std::string theReturn(de.GetByteValue()->GetPointer(), theValLen);
    return theReturn;
  }
  return blank;
}

//each plane needs to know the SOPClassUID, and that won't change from image to image
//so, retrieve this once at the start of writing.
std::string DirectoryHelper::GetSOPClassUID(const std::vector<DataSet>& inDS)
{
  Tag theSOPClassUID(0x0008, 0x0016);
  std::string blank;//return only if there's a problem
  if (inDS[0].FindDataElement(theSOPClassUID)){
    DataElement de = inDS[0].GetDataElement(theSOPClassUID);
    const ByteValue* theVal = de.GetByteValue();
    size_t theValLen = theVal->GetLength();
    std::string theReturn(de.GetByteValue()->GetPointer(), theValLen);
    return theReturn;
  }
  return blank;
}

//retrieve the frame of reference from the set of datasets
std::string DirectoryHelper::GetFrameOfReference(const std::vector<DataSet>& inDS){

  Tag theSOPClassUID(0x0020, 0x0052);
  std::string blank;//return only if there's a problem
  if (inDS[0].FindDataElement(theSOPClassUID)){
    DataElement de = inDS[0].GetDataElement(theSOPClassUID);
    const ByteValue* theVal = de.GetByteValue();
    size_t theValLen = theVal->GetLength();
    std::string theReturn(de.GetByteValue()->GetPointer(), theValLen);
    return theReturn;
  }
  return blank;
}


//----------------------------------------------------------------------------
//used by the vtkGDCMImageReader and vtkGDCMPolyDataReader. Could be used elsewhere, I suppose.
std::string DirectoryHelper::GetStringValueFromTag(const Tag& t, const DataSet& ds)
{
  std::string buffer;

  if( ds.FindDataElement( t ) )
    {
    const DataElement& de = ds.GetDataElement( t );
    const ByteValue *bv = de.GetByteValue();
    if( bv ) // Can be Type 2
      {
      buffer = std::string( bv->GetPointer(), bv->GetLength() );
      // Will be padded with at least one \0
      }
    }

  // Since return is a const char* the very first \0 will be considered
  return buffer.c_str(); // Yes, I mean .c_str()
}
} // end namespace gdcm