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