File: TestDICOMRealWorldValue.cxx

package info (click to toggle)
vtk-dicom 0.8.17-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,176 kB
  • sloc: cpp: 113,811; python: 2,041; makefile: 43; tcl: 10
file content (138 lines) | stat: -rw-r--r-- 4,295 bytes parent folder | download | duplicates (5)
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
#include "vtkDICOMMetaData.h"
#include "vtkDICOMFileSorter.h"
#include "vtkDICOMReader.h"
#include "vtkDICOMTagPath.h"
#include "vtkDICOMSequence.h"
#include "vtkDICOMItem.h"

#include "vtkSmartPointer.h"
#include "vtkStringArray.h"

#include <sstream>

#include <string.h>
#include <stdlib.h>
#include <math.h>

// macro for performing tests
#define TestAssert(t) \
if (!(t)) \
{ \
  cout << exename << ": Assertion Failed: " << #t << "\n"; \
  cout << __FILE__ << ":" << __LINE__ << "\n"; \
  cout.flush(); \
  rval |= 1; \
}

int main(int argc, char *argv[])
{
  int rval = 0;
  const char *exename = argv[0];

  // remove path portion of exename
  const char *cp = exename + strlen(exename);
  while (cp != exename && cp[-1] != '\\' && cp[-1] != '/') { --cp; }
  exename = cp;

  vtkSmartPointer<vtkDICOMFileSorter> sorter =
    vtkSmartPointer<vtkDICOMFileSorter>::New();

  vtkSmartPointer<vtkStringArray> files =
    vtkSmartPointer<vtkStringArray>::New();

  for (int i = 1; i < argc; i++)
  {
    files->InsertNextValue(argv[i]);
  }

  sorter->SetInputFileNames(files);
  sorter->Update();

  vtkSmartPointer<vtkDICOMMetaData> meta =
    vtkSmartPointer<vtkDICOMMetaData>::New();

  if (sorter->GetNumberOfSeries() > 0)
  {
    // read the meta data from the supplied image
    vtkStringArray *a = sorter->GetFileNamesForSeries(0);

    vtkSmartPointer<vtkDICOMReader> reader =
    vtkSmartPointer<vtkDICOMReader>::New();
    reader->SetFileNames(a);
    reader->UpdateInformation();

    meta = reader->GetMetaData();
  }
  else if (argc == 1)
  {
    // create a real world value mapping sequence by hand
    // 1) use Unified Code for Units of Measure (UCUM), version 1.9
    // 2) the CodeMeaning should be a copy of CodeValue unless:
    // 2a) CodeValue=1, in which case use CodeMeaning=unity
    vtkDICOMItem unitsItem;
    unitsItem.Set(DC::CodeValue, "m2/s");
    unitsItem.Set(DC::CodingSchemeDesignator, "UCUM");
    unitsItem.Set(DC::CodingSchemeVersion, "1.9");
    unitsItem.Set(DC::CodeMeaning, "m2/s");

    vtkDICOMItem mappingItem;
    mappingItem.Set(DC::LUTExplanation, "Hot Metal");
    mappingItem.Set(DC::MeasurementUnitsCodeSequence,
      vtkDICOMValue(vtkDICOMVR::SQ, unitsItem));
    mappingItem.Set(DC::LUTLabel, "HOT_METAL");
    // need to explicitly define the VR for these, because it depends
    // on whether the PixelRepresentation is signed or unsigned
    mappingItem.Set(DC::RealWorldValueFirstValueMapped,
                                  vtkDICOMValue(vtkDICOMVR::US, 0));
    mappingItem.Set(DC::RealWorldValueLastValueMapped,
                                  vtkDICOMValue(vtkDICOMVR::US, 4095));
    mappingItem.Set(DC::RealWorldValueIntercept, 0.234);
    mappingItem.Set(DC::RealWorldValueSlope, 0.438);

    meta->Set(DC::RealWorldValueMappingSequence,
      vtkDICOMValue(vtkDICOMVR::SQ, mappingItem));
  }
  else
  {
    cout << "The provided file is not DICOM!" << endl;
  }

  if (meta->Has(DC::RealWorldValueMappingSequence))
  {
    const vtkDICOMItem& mappingItem =
      meta->Get(DC::RealWorldValueMappingSequence).GetItem(0);

    std::string lutName = mappingItem.Get(DC::LUTLabel).AsString();

    std::string units = mappingItem.Get(vtkDICOMTagPath(
      DC::MeasurementUnitsCodeSequence, 0, DC::CodeValue)).AsString();

    double range[2];
    range[0] = mappingItem.Get(DC::RealWorldValueFirstValueMapped).AsDouble();
    range[1] = mappingItem.Get(DC::RealWorldValueLastValueMapped).AsDouble();

    double slope = mappingItem.Get(DC::RealWorldValueSlope).AsDouble();
    double inter = mappingItem.Get(DC::RealWorldValueIntercept).AsDouble();

    cout << "Map pixel values in the range " << range[0] << ", " << range[1] << endl;
    cout << "through the equation y = " << slope << " * x + " << inter << endl;
    cout << "to real values with units of " << units << endl;
    cout << "and display the result with color table " << lutName << endl;

    if (argc == 1)
    {
      TestAssert(range[0] == 0);
      TestAssert(range[1] == 4095);
      TestAssert(fabs(slope - 0.438) < 1e-16);
      TestAssert(fabs(inter - 0.234) < 1e-16);
      TestAssert(units == "m2/s");
      TestAssert(lutName == "HOT_METAL");
    }
  }
  else
  {
    cout << "Image has no real world value mapping!" << endl;
  }

  return rval;
}