comparison Framework/Toolbox/DicomFrameConverter.cpp @ 119:ba83e38cf3ff wasm

rendering of rt-dose
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 02 Oct 2017 22:01:41 +0200
parents a4d0b6c82b29
children 063f7f3d9f14
comparison
equal deleted inserted replaced
118:a4d0b6c82b29 119:ba83e38cf3ff
37 hasRescale_ = false; 37 hasRescale_ = false;
38 rescaleIntercept_ = 0; 38 rescaleIntercept_ = 0;
39 rescaleSlope_ = 1; 39 rescaleSlope_ = 1;
40 defaultWindowCenter_ = 128; 40 defaultWindowCenter_ = 128;
41 defaultWindowWidth_ = 256; 41 defaultWindowWidth_ = 256;
42 } 42 expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
43
44
45 Orthanc::PixelFormat DicomFrameConverter::GetExpectedPixelFormat() const
46 {
47 // TODO Add more checks, e.g. on the number of bytes per value
48 // (cf. DicomImageInformation.h in Orthanc)
49
50 if (isColor_)
51 {
52 return Orthanc::PixelFormat_RGB24;
53 }
54 else if (isSigned_)
55 {
56 return Orthanc::PixelFormat_SignedGrayscale16;
57 }
58 else
59 {
60 return Orthanc::PixelFormat_Grayscale16;
61 }
62 } 43 }
63 44
64 45
65 void DicomFrameConverter::ReadParameters(const Orthanc::DicomMap& dicom) 46 void DicomFrameConverter::ReadParameters(const Orthanc::DicomMap& dicom)
66 { 47 {
83 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 64 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
84 } 65 }
85 66
86 isSigned_ = (tmp == 1); 67 isSigned_ = (tmp == 1);
87 68
88 if (dicom.ParseFloat(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) && 69 double doseGridScaling;
89 dicom.ParseFloat(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE)) 70 bool isRTDose = false;
71
72 if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) &&
73 dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE))
90 { 74 {
91 hasRescale_ = true; 75 hasRescale_ = true;
76 }
77 else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING))
78 {
79 // This is for RT-DOSE
80 hasRescale_ = true;
81 isRTDose = true;
82 rescaleIntercept_ = 0;
83 rescaleSlope_ = doseGridScaling;
92 } 84 }
93 85
94 std::string photometric; 86 std::string photometric;
95 if (dicom.CopyToString(photometric, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false)) 87 if (dicom.CopyToString(photometric, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false))
96 { 88 {
102 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 94 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
103 } 95 }
104 96
105 isColor_ = (photometric != "MONOCHROME1" && 97 isColor_ = (photometric != "MONOCHROME1" &&
106 photometric != "MONOCHROME2"); 98 photometric != "MONOCHROME2");
99
100 // TODO Add more checks, e.g. on the number of bytes per value
101 // (cf. DicomImageInformation.h in Orthanc)
102
103 if (isRTDose)
104 {
105 expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32;
106 }
107 else if (isColor_)
108 {
109 expectedPixelFormat_ = Orthanc::PixelFormat_RGB24;
110 }
111 else if (isSigned_)
112 {
113 expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16;
114 }
115 else
116 {
117 expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
118 }
107 } 119 }
108 120
109 121
110 void DicomFrameConverter::ConvertFrame(std::auto_ptr<Orthanc::ImageAccessor>& source) const 122 void DicomFrameConverter::ConvertFrame(std::auto_ptr<Orthanc::ImageAccessor>& source) const
111 { 123 {
128 // No conversion has to be done 140 // No conversion has to be done
129 return; 141 return;
130 } 142 }
131 143
132 assert(sourceFormat == Orthanc::PixelFormat_Grayscale16 || 144 assert(sourceFormat == Orthanc::PixelFormat_Grayscale16 ||
145 sourceFormat == Orthanc::PixelFormat_Grayscale32 ||
133 sourceFormat == Orthanc::PixelFormat_SignedGrayscale16); 146 sourceFormat == Orthanc::PixelFormat_SignedGrayscale16);
134 147
135 // This is the case of a grayscale frame. Convert it to Float32. 148 // This is the case of a grayscale frame. Convert it to Float32.
136 std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 149 std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32,
137 source->GetWidth(), 150 source->GetWidth(),
140 Orthanc::ImageProcessing::Convert(*converted, *source); 153 Orthanc::ImageProcessing::Convert(*converted, *source);
141 154
142 source.reset(NULL); // We don't need the source frame anymore 155 source.reset(NULL); // We don't need the source frame anymore
143 156
144 // Correct rescale slope/intercept if need be 157 // Correct rescale slope/intercept if need be
158 ApplyRescale(*converted, sourceFormat != Orthanc::PixelFormat_Grayscale32);
159
160 source = converted;
161 }
162
163
164 void DicomFrameConverter::ApplyRescale(Orthanc::ImageAccessor& image,
165 bool useDouble) const
166 {
167 if (image.GetFormat() != Orthanc::PixelFormat_Float32)
168 {
169 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
170 }
171
145 if (hasRescale_) 172 if (hasRescale_)
146 { 173 {
147 for (unsigned int y = 0; y < converted->GetHeight(); y++) 174 for (unsigned int y = 0; y < image.GetHeight(); y++)
148 { 175 {
149 float* p = reinterpret_cast<float*>(converted->GetRow(y)); 176 float* p = reinterpret_cast<float*>(image.GetRow(y));
150 for (unsigned int x = 0; x < converted->GetWidth(); x++, p++) 177
178 if (useDouble)
151 { 179 {
152 float value = *p; 180 // Slower, accurate implementation using double
153 181 for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
154 if (hasRescale_)
155 { 182 {
156 value = value * rescaleSlope_ + rescaleIntercept_; 183 double value = static_cast<double>(*p);
184 *p = static_cast<float>(value * rescaleSlope_ + rescaleIntercept_);
157 } 185 }
158 186 }
159 *p = value; 187 else
188 {
189 // Fast, approximate implementation using float
190 for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
191 {
192 *p = (*p) * static_cast<float>(rescaleSlope_) + static_cast<float>(rescaleIntercept_);
193 }
160 } 194 }
161 } 195 }
162 } 196 }
163 197 }
164 source = converted; 198
165 } 199
200 double DicomFrameConverter::Apply(double x) const
201 {
202 return x * rescaleSlope_ + rescaleIntercept_;
203 }
204
166 } 205 }