Mercurial > hg > orthanc-stone
annotate 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 |
rev | line source |
---|---|
0 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
40
7207a407bcd8
shared copyright with osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
34
diff
changeset
|
5 * Copyright (C) 2017 Osimis, Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
47 | 8 * modify it under the terms of the GNU Affero General Public License |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
0 | 11 * |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
47 | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
0 | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 **/ | |
20 | |
21 | |
22 #include "DicomFrameConverter.h" | |
23 | |
32 | 24 #include "GeometryToolbox.h" |
25 | |
113
2eca030792aa
using the Orthanc Framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
26 #include <Core/Images/Image.h> |
2eca030792aa
using the Orthanc Framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
27 #include <Core/Images/ImageProcessing.h> |
2eca030792aa
using the Orthanc Framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
28 #include <Core/OrthancException.h> |
2eca030792aa
using the Orthanc Framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
29 #include <Core/Toolbox.h> |
0 | 30 |
31 namespace OrthancStone | |
32 { | |
33 void DicomFrameConverter::SetDefaultParameters() | |
34 { | |
35 isSigned_ = true; | |
36 isColor_ = false; | |
37 hasRescale_ = false; | |
38 rescaleIntercept_ = 0; | |
39 rescaleSlope_ = 1; | |
40 defaultWindowCenter_ = 128; | |
41 defaultWindowWidth_ = 256; | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
42 expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; |
0 | 43 } |
44 | |
45 | |
118
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
46 void DicomFrameConverter::ReadParameters(const Orthanc::DicomMap& dicom) |
0 | 47 { |
48 SetDefaultParameters(); | |
49 | |
32 | 50 Vector c, w; |
118
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
51 if (GeometryToolbox::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) && |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
52 GeometryToolbox::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) && |
34 | 53 c.size() > 0 && |
54 w.size() > 0) | |
0 | 55 { |
34 | 56 defaultWindowCenter_ = static_cast<float>(c[0]); |
57 defaultWindowWidth_ = static_cast<float>(w[0]); | |
0 | 58 } |
59 | |
118
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
60 int32_t tmp; |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
61 if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION)) |
0 | 62 { |
32 | 63 // Type 1 tag, must be present |
64 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
65 } | |
66 | |
67 isSigned_ = (tmp == 1); | |
68 | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
69 double doseGridScaling; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
70 bool isRTDose = false; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
71 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
72 if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) && |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
73 dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE)) |
32 | 74 { |
0 | 75 hasRescale_ = true; |
76 } | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
77 else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING)) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
78 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
79 // This is for RT-DOSE |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
80 hasRescale_ = true; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
81 isRTDose = true; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
82 rescaleIntercept_ = 0; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
83 rescaleSlope_ = doseGridScaling; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
84 } |
0 | 85 |
118
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
86 std::string photometric; |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
87 if (dicom.CopyToString(photometric, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false)) |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
88 { |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
89 photometric = Orthanc::Toolbox::StripSpaces(photometric); |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
90 } |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
91 else |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
92 { |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
93 // Type 1 tag, must be present |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
94 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
95 } |
a4d0b6c82b29
using Orthanc::DicomMap instead of OrthancPlugins::DicomDatasetReader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
96 |
0 | 97 isColor_ = (photometric != "MONOCHROME1" && |
98 photometric != "MONOCHROME2"); | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
99 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
100 // TODO Add more checks, e.g. on the number of bytes per value |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
101 // (cf. DicomImageInformation.h in Orthanc) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
102 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
103 if (isRTDose) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
104 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
105 expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
106 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
107 else if (isColor_) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
108 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
109 expectedPixelFormat_ = Orthanc::PixelFormat_RGB24; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
110 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
111 else if (isSigned_) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
112 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
113 expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
114 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
115 else |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
116 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
117 expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
118 } |
0 | 119 } |
120 | |
121 | |
122 void DicomFrameConverter::ConvertFrame(std::auto_ptr<Orthanc::ImageAccessor>& source) const | |
123 { | |
124 assert(sizeof(float) == 4); | |
125 | |
126 if (source.get() == NULL) | |
127 { | |
128 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
129 } | |
130 | |
131 Orthanc::PixelFormat sourceFormat = source->GetFormat(); | |
132 | |
133 if (sourceFormat != GetExpectedPixelFormat()) | |
134 { | |
135 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); | |
136 } | |
137 | |
138 if (sourceFormat == Orthanc::PixelFormat_RGB24) | |
139 { | |
140 // No conversion has to be done | |
141 return; | |
142 } | |
143 | |
144 assert(sourceFormat == Orthanc::PixelFormat_Grayscale16 || | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
145 sourceFormat == Orthanc::PixelFormat_Grayscale32 || |
0 | 146 sourceFormat == Orthanc::PixelFormat_SignedGrayscale16); |
147 | |
148 // This is the case of a grayscale frame. Convert it to Float32. | |
149 std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, | |
150 source->GetWidth(), | |
11 | 151 source->GetHeight(), |
152 false)); | |
0 | 153 Orthanc::ImageProcessing::Convert(*converted, *source); |
154 | |
155 source.reset(NULL); // We don't need the source frame anymore | |
156 | |
157 // Correct rescale slope/intercept if need be | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
158 ApplyRescale(*converted, sourceFormat != Orthanc::PixelFormat_Grayscale32); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
159 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
160 source = converted; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
161 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
162 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
163 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
164 void DicomFrameConverter::ApplyRescale(Orthanc::ImageAccessor& image, |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
165 bool useDouble) const |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
166 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
167 if (image.GetFormat() != Orthanc::PixelFormat_Float32) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
168 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
169 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
170 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
171 |
0 | 172 if (hasRescale_) |
173 { | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
174 for (unsigned int y = 0; y < image.GetHeight(); y++) |
0 | 175 { |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
176 float* p = reinterpret_cast<float*>(image.GetRow(y)); |
0 | 177 |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
178 if (useDouble) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
179 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
180 // Slower, accurate implementation using double |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
181 for (unsigned int x = 0; x < image.GetWidth(); x++, p++) |
0 | 182 { |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
183 double value = static_cast<double>(*p); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
184 *p = static_cast<float>(value * rescaleSlope_ + rescaleIntercept_); |
0 | 185 } |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
186 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
187 else |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
188 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
189 // Fast, approximate implementation using float |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
190 for (unsigned int x = 0; x < image.GetWidth(); x++, p++) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
191 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
192 *p = (*p) * static_cast<float>(rescaleSlope_) + static_cast<float>(rescaleIntercept_); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
193 } |
0 | 194 } |
195 } | |
196 } | |
197 } | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
198 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
199 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
200 double DicomFrameConverter::Apply(double x) const |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
201 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
202 return x * rescaleSlope_ + rescaleIntercept_; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
203 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
118
diff
changeset
|
204 |
0 | 205 } |