comparison Framework/Volumes/ImageBuffer3D.cpp @ 0:351ab0da0150

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 14 Oct 2016 15:34:11 +0200
parents
children 4b7e0244881f
comparison
equal deleted inserted replaced
-1:000000000000 0:351ab0da0150
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * In addition, as a special exception, the copyright holders of this
12 * program give permission to link the code of its release with the
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
14 * that use the same license as the "OpenSSL" library), and distribute
15 * the linked executables. You must obey the GNU General Public License
16 * in all respects for all of the code used other than "OpenSSL". If you
17 * modify file(s) with this exception, you may extend this exception to
18 * your version of the file(s), but you are not obligated to do so. If
19 * you do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source files
21 * in the program, then also delete it here.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/
31
32
33 #include "ImageBuffer3D.h"
34
35 #include "../Orthanc/Core/Images/ImageProcessing.h"
36 #include "../Orthanc/Core/OrthancException.h"
37
38 namespace OrthancStone
39 {
40 Orthanc::ImageAccessor ImageBuffer3D::GetAxialSliceAccessor(unsigned int slice,
41 bool readOnly)
42 {
43 if (slice >= depth_)
44 {
45 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
46 }
47
48 Orthanc::ImageAccessor accessor;
49
50 if (readOnly)
51 {
52 accessor.AssignReadOnly(format_, width_, height_, image_.GetPitch(),
53 image_.GetConstRow(height_ * (depth_ - 1 - slice)));
54 }
55 else
56 {
57 accessor.AssignWritable(format_, width_, height_, image_.GetPitch(),
58 image_.GetRow(height_ * (depth_ - 1 - slice)));
59 }
60
61 return accessor;
62 }
63
64
65 Orthanc::ImageAccessor ImageBuffer3D::GetCoronalSliceAccessor(unsigned int slice,
66 bool readOnly)
67 {
68 if (slice >= height_)
69 {
70 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
71 }
72
73 Orthanc::ImageAccessor accessor;
74
75 if (readOnly)
76 {
77 accessor.AssignReadOnly(format_, width_, depth_, image_.GetPitch() * height_,
78 image_.GetConstRow(slice));
79 }
80 else
81 {
82 accessor.AssignWritable(format_, width_, depth_, image_.GetPitch() * height_,
83 image_.GetRow(slice));
84 }
85
86 return accessor;
87 }
88
89
90 Orthanc::Image* ImageBuffer3D::ExtractSagittalSlice(unsigned int slice) const
91 {
92 if (slice >= width_)
93 {
94 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
95 }
96
97 std::auto_ptr<Orthanc::Image> result(new Orthanc::Image(format_, height_, depth_));
98
99 unsigned int bytesPerPixel = Orthanc::GetBytesPerPixel(format_);
100
101 for (unsigned int z = 0; z < depth_; z++)
102 {
103 //uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(depth_ - 1 - z));
104 uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(z));
105
106 for (unsigned int y = 0; y < height_; y++)
107 {
108 const void* source = (reinterpret_cast<const uint8_t*>(image_.GetConstRow(y + z * height_)) +
109 bytesPerPixel * slice);
110
111 memcpy(target, source, bytesPerPixel);
112 target += bytesPerPixel;
113 }
114 }
115
116 return result.release();
117 }
118
119
120 ImageBuffer3D::ImageBuffer3D(Orthanc::PixelFormat format,
121 unsigned int width,
122 unsigned int height,
123 unsigned int depth) :
124 image_(format, width, height * depth),
125 format_(format),
126 width_(width),
127 height_(height),
128 depth_(depth)
129 {
130 GeometryToolbox::AssignVector(voxelDimensions_, 1, 1, 1);
131 }
132
133
134 void ImageBuffer3D::Clear()
135 {
136 WriteLock lock(mutex_);
137 Orthanc::ImageProcessing::Set(image_, 0);
138 }
139
140
141 void ImageBuffer3D::SetAxialGeometry(const SliceGeometry& geometry)
142 {
143 WriteLock lock(mutex_);
144 axialGeometry_ = geometry;
145 }
146
147
148 void ImageBuffer3D::SetVoxelDimensions(double x,
149 double y,
150 double z)
151 {
152 if (x <= 0 ||
153 y <= 0 ||
154 z <= 0)
155 {
156 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
157 }
158
159 {
160 WriteLock lock(mutex_);
161 GeometryToolbox::AssignVector(voxelDimensions_, x, y, z);
162 }
163 }
164
165
166 Vector ImageBuffer3D::GetVoxelDimensions(VolumeProjection projection)
167 {
168 ReadLock lock(mutex_);
169
170 Vector result;
171 switch (projection)
172 {
173 case VolumeProjection_Axial:
174 result = voxelDimensions_;
175 break;
176
177 case VolumeProjection_Coronal:
178 GeometryToolbox::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]);
179 break;
180
181 case VolumeProjection_Sagittal:
182 GeometryToolbox::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]);
183 break;
184
185 default:
186 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
187 }
188
189 return result;
190 }
191
192
193 void ImageBuffer3D::GetSliceSize(unsigned int& width,
194 unsigned int& height,
195 VolumeProjection projection)
196 {
197 switch (projection)
198 {
199 case VolumeProjection_Axial:
200 width = width_;
201 height = height_;
202 break;
203
204 case VolumeProjection_Coronal:
205 width = width_;
206 height = depth_;
207 break;
208
209 case VolumeProjection_Sagittal:
210 width = height_;
211 height = depth_;
212 break;
213
214 default:
215 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
216 }
217 }
218
219
220 ParallelSlices* ImageBuffer3D::GetGeometry(VolumeProjection projection)
221 {
222 std::auto_ptr<ParallelSlices> result(new ParallelSlices);
223
224 switch (projection)
225 {
226 case VolumeProjection_Axial:
227 for (unsigned int z = 0; z < depth_; z++)
228 {
229 Vector origin = axialGeometry_.GetOrigin();
230 origin += static_cast<double>(z) * voxelDimensions_[2] * axialGeometry_.GetNormal();
231
232 result->AddSlice(origin,
233 axialGeometry_.GetAxisX(),
234 axialGeometry_.GetAxisY());
235 }
236 break;
237
238 case VolumeProjection_Coronal:
239 for (unsigned int y = 0; y < height_; y++)
240 {
241 Vector origin = axialGeometry_.GetOrigin();
242 origin += static_cast<double>(y) * voxelDimensions_[1] * axialGeometry_.GetAxisY();
243 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal();
244
245 result->AddSlice(origin,
246 axialGeometry_.GetAxisX(),
247 -axialGeometry_.GetNormal());
248 }
249 break;
250
251 case VolumeProjection_Sagittal:
252 for (unsigned int x = 0; x < width_; x++)
253 {
254 Vector origin = axialGeometry_.GetOrigin();
255 origin += static_cast<double>(x) * voxelDimensions_[0] * axialGeometry_.GetAxisX();
256 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal();
257
258 result->AddSlice(origin,
259 axialGeometry_.GetAxisY(),
260 -axialGeometry_.GetNormal());
261 }
262 break;
263
264 default:
265 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
266 }
267
268 return result.release();
269 }
270
271
272 ImageBuffer3D::SliceReader::SliceReader(ImageBuffer3D& that,
273 VolumeProjection projection,
274 unsigned int slice) :
275 lock_(that.mutex_)
276 {
277 switch (projection)
278 {
279 case VolumeProjection_Axial:
280 accessor_ = that.GetAxialSliceAccessor(slice, true);
281 break;
282
283 case VolumeProjection_Coronal:
284 accessor_ = that.GetCoronalSliceAccessor(slice, true);
285 break;
286
287 case VolumeProjection_Sagittal:
288 sagittal_.reset(that.ExtractSagittalSlice(slice));
289 accessor_ = *sagittal_;
290 break;
291
292 default:
293 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
294 }
295 }
296
297
298 void ImageBuffer3D::SliceWriter::Flush()
299 {
300 if (sagittal_.get() != NULL)
301 {
302 // TODO
303 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
304 }
305 }
306
307
308 ImageBuffer3D::SliceWriter::SliceWriter(ImageBuffer3D& that,
309 VolumeProjection projection,
310 unsigned int slice) :
311 lock_(that.mutex_)
312 {
313 switch (projection)
314 {
315 case VolumeProjection_Axial:
316 accessor_ = that.GetAxialSliceAccessor(slice, false);
317 break;
318
319 case VolumeProjection_Coronal:
320 accessor_ = that.GetCoronalSliceAccessor(slice, false);
321 break;
322
323 case VolumeProjection_Sagittal:
324 sagittal_.reset(that.ExtractSagittalSlice(slice));
325 accessor_ = *sagittal_;
326 break;
327
328 default:
329 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
330 }
331 }
332 }