Mercurial > hg > orthanc-stone
annotate Framework/Volumes/ImageBuffer3D.cpp @ 105:e0ddd8cad909 wasm
cleaning
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 01 Jun 2017 12:33:24 +0200 |
parents | 4a541cd4fa83 |
children | 53025eecbc95 |
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:
16
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 "ImageBuffer3D.h" | |
23 | |
16 | 24 #include "../../Resources/Orthanc/Core/Images/ImageProcessing.h" |
105 | 25 #include "../../Resources/Orthanc/Core/Logging.h" |
16 | 26 #include "../../Resources/Orthanc/Core/OrthancException.h" |
0 | 27 |
87
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
28 #include <string.h> |
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
29 |
0 | 30 namespace OrthancStone |
31 { | |
32 Orthanc::ImageAccessor ImageBuffer3D::GetAxialSliceAccessor(unsigned int slice, | |
33 bool readOnly) | |
34 { | |
35 if (slice >= depth_) | |
36 { | |
37 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
38 } | |
39 | |
40 Orthanc::ImageAccessor accessor; | |
41 | |
42 if (readOnly) | |
43 { | |
44 accessor.AssignReadOnly(format_, width_, height_, image_.GetPitch(), | |
45 image_.GetConstRow(height_ * (depth_ - 1 - slice))); | |
46 } | |
47 else | |
48 { | |
49 accessor.AssignWritable(format_, width_, height_, image_.GetPitch(), | |
50 image_.GetRow(height_ * (depth_ - 1 - slice))); | |
51 } | |
52 | |
53 return accessor; | |
54 } | |
55 | |
56 | |
57 Orthanc::ImageAccessor ImageBuffer3D::GetCoronalSliceAccessor(unsigned int slice, | |
58 bool readOnly) | |
59 { | |
60 if (slice >= height_) | |
61 { | |
62 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
63 } | |
64 | |
65 Orthanc::ImageAccessor accessor; | |
66 | |
67 if (readOnly) | |
68 { | |
69 accessor.AssignReadOnly(format_, width_, depth_, image_.GetPitch() * height_, | |
70 image_.GetConstRow(slice)); | |
71 } | |
72 else | |
73 { | |
74 accessor.AssignWritable(format_, width_, depth_, image_.GetPitch() * height_, | |
75 image_.GetRow(slice)); | |
76 } | |
77 | |
78 return accessor; | |
79 } | |
80 | |
81 | |
82 Orthanc::Image* ImageBuffer3D::ExtractSagittalSlice(unsigned int slice) const | |
83 { | |
84 if (slice >= width_) | |
85 { | |
86 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
87 } | |
88 | |
11 | 89 std::auto_ptr<Orthanc::Image> result(new Orthanc::Image(format_, height_, depth_, false)); |
0 | 90 |
91 unsigned int bytesPerPixel = Orthanc::GetBytesPerPixel(format_); | |
92 | |
93 for (unsigned int z = 0; z < depth_; z++) | |
94 { | |
95 //uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(depth_ - 1 - z)); | |
96 uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(z)); | |
97 | |
98 for (unsigned int y = 0; y < height_; y++) | |
99 { | |
100 const void* source = (reinterpret_cast<const uint8_t*>(image_.GetConstRow(y + z * height_)) + | |
101 bytesPerPixel * slice); | |
102 | |
103 memcpy(target, source, bytesPerPixel); | |
104 target += bytesPerPixel; | |
105 } | |
106 } | |
107 | |
108 return result.release(); | |
109 } | |
110 | |
111 | |
112 ImageBuffer3D::ImageBuffer3D(Orthanc::PixelFormat format, | |
113 unsigned int width, | |
114 unsigned int height, | |
115 unsigned int depth) : | |
11 | 116 image_(format, width, height * depth, false), |
0 | 117 format_(format), |
118 width_(width), | |
119 height_(height), | |
120 depth_(depth) | |
121 { | |
122 GeometryToolbox::AssignVector(voxelDimensions_, 1, 1, 1); | |
105 | 123 |
124 LOG(INFO) << "Created an image of " | |
125 << (GetEstimatedMemorySize() / (1024ll * 1024ll)) << "MB"; | |
0 | 126 } |
127 | |
128 | |
129 void ImageBuffer3D::Clear() | |
130 { | |
87
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
131 memset(image_.GetBuffer(), 0, image_.GetHeight() * image_.GetPitch()); |
0 | 132 } |
133 | |
134 | |
135 void ImageBuffer3D::SetAxialGeometry(const SliceGeometry& geometry) | |
136 { | |
137 axialGeometry_ = geometry; | |
138 } | |
139 | |
140 | |
141 void ImageBuffer3D::SetVoxelDimensions(double x, | |
142 double y, | |
143 double z) | |
144 { | |
145 if (x <= 0 || | |
146 y <= 0 || | |
147 z <= 0) | |
148 { | |
149 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
150 } | |
151 | |
152 { | |
153 GeometryToolbox::AssignVector(voxelDimensions_, x, y, z); | |
154 } | |
155 } | |
156 | |
157 | |
158 Vector ImageBuffer3D::GetVoxelDimensions(VolumeProjection projection) | |
159 { | |
160 Vector result; | |
161 switch (projection) | |
162 { | |
163 case VolumeProjection_Axial: | |
164 result = voxelDimensions_; | |
165 break; | |
166 | |
167 case VolumeProjection_Coronal: | |
168 GeometryToolbox::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]); | |
169 break; | |
170 | |
171 case VolumeProjection_Sagittal: | |
172 GeometryToolbox::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]); | |
173 break; | |
174 | |
175 default: | |
176 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
177 } | |
178 | |
179 return result; | |
180 } | |
181 | |
182 | |
183 void ImageBuffer3D::GetSliceSize(unsigned int& width, | |
184 unsigned int& height, | |
185 VolumeProjection projection) | |
186 { | |
187 switch (projection) | |
188 { | |
189 case VolumeProjection_Axial: | |
190 width = width_; | |
191 height = height_; | |
192 break; | |
193 | |
194 case VolumeProjection_Coronal: | |
195 width = width_; | |
196 height = depth_; | |
197 break; | |
198 | |
199 case VolumeProjection_Sagittal: | |
200 width = height_; | |
201 height = depth_; | |
202 break; | |
203 | |
204 default: | |
205 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
206 } | |
207 } | |
208 | |
209 | |
210 ParallelSlices* ImageBuffer3D::GetGeometry(VolumeProjection projection) | |
211 { | |
212 std::auto_ptr<ParallelSlices> result(new ParallelSlices); | |
213 | |
214 switch (projection) | |
215 { | |
216 case VolumeProjection_Axial: | |
217 for (unsigned int z = 0; z < depth_; z++) | |
218 { | |
219 Vector origin = axialGeometry_.GetOrigin(); | |
220 origin += static_cast<double>(z) * voxelDimensions_[2] * axialGeometry_.GetNormal(); | |
221 | |
222 result->AddSlice(origin, | |
223 axialGeometry_.GetAxisX(), | |
224 axialGeometry_.GetAxisY()); | |
225 } | |
226 break; | |
227 | |
228 case VolumeProjection_Coronal: | |
229 for (unsigned int y = 0; y < height_; y++) | |
230 { | |
231 Vector origin = axialGeometry_.GetOrigin(); | |
232 origin += static_cast<double>(y) * voxelDimensions_[1] * axialGeometry_.GetAxisY(); | |
233 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); | |
234 | |
235 result->AddSlice(origin, | |
236 axialGeometry_.GetAxisX(), | |
237 -axialGeometry_.GetNormal()); | |
238 } | |
239 break; | |
240 | |
241 case VolumeProjection_Sagittal: | |
242 for (unsigned int x = 0; x < width_; x++) | |
243 { | |
244 Vector origin = axialGeometry_.GetOrigin(); | |
245 origin += static_cast<double>(x) * voxelDimensions_[0] * axialGeometry_.GetAxisX(); | |
246 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); | |
247 | |
248 result->AddSlice(origin, | |
249 axialGeometry_.GetAxisY(), | |
250 -axialGeometry_.GetNormal()); | |
251 } | |
252 break; | |
253 | |
254 default: | |
255 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
256 } | |
257 | |
258 return result.release(); | |
259 } | |
260 | |
261 | |
105 | 262 uint64_t ImageBuffer3D::GetEstimatedMemorySize() const |
263 { | |
264 return image_.GetPitch() * image_.GetHeight() * Orthanc::GetBytesPerPixel(format_); | |
265 } | |
266 | |
267 | |
0 | 268 ImageBuffer3D::SliceReader::SliceReader(ImageBuffer3D& that, |
269 VolumeProjection projection, | |
87
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
270 unsigned int slice) |
0 | 271 { |
272 switch (projection) | |
273 { | |
274 case VolumeProjection_Axial: | |
275 accessor_ = that.GetAxialSliceAccessor(slice, true); | |
276 break; | |
277 | |
278 case VolumeProjection_Coronal: | |
279 accessor_ = that.GetCoronalSliceAccessor(slice, true); | |
280 break; | |
281 | |
282 case VolumeProjection_Sagittal: | |
283 sagittal_.reset(that.ExtractSagittalSlice(slice)); | |
284 accessor_ = *sagittal_; | |
285 break; | |
286 | |
287 default: | |
288 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
289 } | |
290 } | |
291 | |
292 | |
293 void ImageBuffer3D::SliceWriter::Flush() | |
294 { | |
87
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
295 if (modified_) |
0 | 296 { |
87
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
297 if (sagittal_.get() != NULL) |
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
298 { |
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
299 // TODO |
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
300 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
301 } |
0 | 302 } |
303 } | |
304 | |
305 | |
306 ImageBuffer3D::SliceWriter::SliceWriter(ImageBuffer3D& that, | |
307 VolumeProjection projection, | |
308 unsigned int slice) : | |
87
4a541cd4fa83
OrthancVolumeImageLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
309 modified_(false) |
0 | 310 { |
311 switch (projection) | |
312 { | |
313 case VolumeProjection_Axial: | |
314 accessor_ = that.GetAxialSliceAccessor(slice, false); | |
315 break; | |
316 | |
317 case VolumeProjection_Coronal: | |
318 accessor_ = that.GetCoronalSliceAccessor(slice, false); | |
319 break; | |
320 | |
321 case VolumeProjection_Sagittal: | |
322 sagittal_.reset(that.ExtractSagittalSlice(slice)); | |
323 accessor_ = *sagittal_; | |
324 break; | |
325 | |
326 default: | |
327 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
328 } | |
329 } | |
330 } |