comparison Framework/Volumes/ImageBuffer3D.cpp @ 318:3a4ca166fafa am-2

ImageAccessor refactoring + implemented Image Cache in SmartLoader
author am@osimis.io
date Mon, 08 Oct 2018 17:10:08 +0200
parents 5412adf19980
children 557c8ff1db5c
comparison
equal deleted inserted replaced
317:b66d13708f40 318:3a4ca166fafa
11 * 11 *
12 * This program is distributed in the hope that it will be useful, but 12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details. 15 * Affero General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Affero General Public License 17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/ 19 **/
20 20
21 21
27 27
28 #include <string.h> 28 #include <string.h>
29 29
30 namespace OrthancStone 30 namespace OrthancStone
31 { 31 {
32 Orthanc::ImageAccessor ImageBuffer3D::GetAxialSliceAccessor(unsigned int slice, 32 void ImageBuffer3D::GetAxialSliceAccessor(Orthanc::ImageAccessor& target,
33 bool readOnly) const 33 unsigned int slice,
34 bool readOnly) const
34 { 35 {
35 if (slice >= depth_) 36 if (slice >= depth_)
36 { 37 {
37 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 38 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
38 } 39 }
39 40
40 Orthanc::ImageAccessor accessor;
41
42 if (readOnly) 41 if (readOnly)
43 { 42 {
44 accessor.AssignReadOnly(format_, width_, height_, image_.GetPitch(), 43 target.AssignReadOnly(format_, width_, height_, image_.GetPitch(),
45 image_.GetConstRow(height_ * (depth_ - 1 - slice))); 44 image_.GetConstRow(height_ * (depth_ - 1 - slice)));
46 } 45 }
47 else 46 else
48 { 47 {
49 accessor.AssignWritable(format_, width_, height_, image_.GetPitch(), 48 target.AssignWritable(format_, width_, height_, image_.GetPitch(),
50 image_.GetRow(height_ * (depth_ - 1 - slice))); 49 image_.GetRow(height_ * (depth_ - 1 - slice)));
51 } 50 }
52 51 }
53 return accessor; 52
54 } 53
55 54 void ImageBuffer3D::GetCoronalSliceAccessor(Orthanc::ImageAccessor& target,
56 55 unsigned int slice,
57 Orthanc::ImageAccessor ImageBuffer3D::GetCoronalSliceAccessor(unsigned int slice, 56 bool readOnly) const
58 bool readOnly) const
59 { 57 {
60 if (slice >= height_) 58 if (slice >= height_)
61 { 59 {
62 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 60 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
63 } 61 }
64 62
65 Orthanc::ImageAccessor accessor;
66
67 if (readOnly) 63 if (readOnly)
68 { 64 {
69 accessor.AssignReadOnly(format_, width_, depth_, image_.GetPitch() * height_, 65 target.AssignReadOnly(format_, width_, depth_, image_.GetPitch() * height_,
70 image_.GetConstRow(slice)); 66 image_.GetConstRow(slice));
71 } 67 }
72 else 68 else
73 { 69 {
74 accessor.AssignWritable(format_, width_, depth_, image_.GetPitch() * height_, 70 target.AssignWritable(format_, width_, depth_, image_.GetPitch() * height_,
75 image_.GetRow(slice)); 71 image_.GetRow(slice));
76 } 72 }
77
78 return accessor;
79 } 73 }
80 74
81 75
82 Orthanc::Image* ImageBuffer3D::ExtractSagittalSlice(unsigned int slice) const 76 Orthanc::Image* ImageBuffer3D::ExtractSagittalSlice(unsigned int slice) const
83 { 77 {
95 //uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(depth_ - 1 - z)); 89 //uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(depth_ - 1 - z));
96 uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(z)); 90 uint8_t* target = reinterpret_cast<uint8_t*>(result->GetRow(z));
97 91
98 for (unsigned int y = 0; y < height_; y++) 92 for (unsigned int y = 0; y < height_; y++)
99 { 93 {
100 const void* source = (reinterpret_cast<const uint8_t*>(image_.GetConstRow(y + z * height_)) + 94 const void* source = (reinterpret_cast<const uint8_t*>(image_.GetConstRow(y + z * height_)) +
101 bytesPerPixel * slice); 95 bytesPerPixel * slice);
102 96
103 memcpy(target, source, bytesPerPixel); 97 memcpy(target, source, bytesPerPixel);
104 target += bytesPerPixel; 98 target += bytesPerPixel;
105 } 99 }
161 Vector ImageBuffer3D::GetVoxelDimensions(VolumeProjection projection) const 155 Vector ImageBuffer3D::GetVoxelDimensions(VolumeProjection projection) const
162 { 156 {
163 Vector result; 157 Vector result;
164 switch (projection) 158 switch (projection)
165 { 159 {
166 case VolumeProjection_Axial: 160 case VolumeProjection_Axial:
167 result = voxelDimensions_; 161 result = voxelDimensions_;
168 break; 162 break;
169 163
170 case VolumeProjection_Coronal: 164 case VolumeProjection_Coronal:
171 LinearAlgebra::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]); 165 LinearAlgebra::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]);
172 break; 166 break;
173 167
174 case VolumeProjection_Sagittal: 168 case VolumeProjection_Sagittal:
175 LinearAlgebra::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]); 169 LinearAlgebra::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]);
176 break; 170 break;
177 171
178 default: 172 default:
179 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 173 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
180 } 174 }
181 175
182 return result; 176 return result;
183 } 177 }
184 178
187 unsigned int& height, 181 unsigned int& height,
188 VolumeProjection projection) 182 VolumeProjection projection)
189 { 183 {
190 switch (projection) 184 switch (projection)
191 { 185 {
192 case VolumeProjection_Axial: 186 case VolumeProjection_Axial:
193 width = width_; 187 width = width_;
194 height = height_; 188 height = height_;
195 break; 189 break;
196 190
197 case VolumeProjection_Coronal: 191 case VolumeProjection_Coronal:
198 width = width_; 192 width = width_;
199 height = depth_; 193 height = depth_;
200 break; 194 break;
201 195
202 case VolumeProjection_Sagittal: 196 case VolumeProjection_Sagittal:
203 width = height_; 197 width = height_;
204 height = depth_; 198 height = depth_;
205 break; 199 break;
206 200
207 default: 201 default:
208 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 202 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
209 } 203 }
210 } 204 }
211 205
212 206
213 ParallelSlices* ImageBuffer3D::GetGeometry(VolumeProjection projection) const 207 ParallelSlices* ImageBuffer3D::GetGeometry(VolumeProjection projection) const
214 { 208 {
215 std::auto_ptr<ParallelSlices> result(new ParallelSlices); 209 std::auto_ptr<ParallelSlices> result(new ParallelSlices);
216 210
217 switch (projection) 211 switch (projection)
218 { 212 {
219 case VolumeProjection_Axial: 213 case VolumeProjection_Axial:
220 for (unsigned int z = 0; z < depth_; z++) 214 for (unsigned int z = 0; z < depth_; z++)
221 { 215 {
222 Vector origin = axialGeometry_.GetOrigin(); 216 Vector origin = axialGeometry_.GetOrigin();
223 origin += static_cast<double>(z) * voxelDimensions_[2] * axialGeometry_.GetNormal(); 217 origin += static_cast<double>(z) * voxelDimensions_[2] * axialGeometry_.GetNormal();
224 218
225 result->AddSlice(origin, 219 result->AddSlice(origin,
226 axialGeometry_.GetAxisX(), 220 axialGeometry_.GetAxisX(),
227 axialGeometry_.GetAxisY()); 221 axialGeometry_.GetAxisY());
228 } 222 }
229 break; 223 break;
230 224
231 case VolumeProjection_Coronal: 225 case VolumeProjection_Coronal:
232 for (unsigned int y = 0; y < height_; y++) 226 for (unsigned int y = 0; y < height_; y++)
233 { 227 {
234 Vector origin = axialGeometry_.GetOrigin(); 228 Vector origin = axialGeometry_.GetOrigin();
235 origin += static_cast<double>(y) * voxelDimensions_[1] * axialGeometry_.GetAxisY(); 229 origin += static_cast<double>(y) * voxelDimensions_[1] * axialGeometry_.GetAxisY();
236 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); 230 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal();
237 231
238 result->AddSlice(origin, 232 result->AddSlice(origin,
239 axialGeometry_.GetAxisX(), 233 axialGeometry_.GetAxisX(),
240 -axialGeometry_.GetNormal()); 234 -axialGeometry_.GetNormal());
241 } 235 }
242 break; 236 break;
243 237
244 case VolumeProjection_Sagittal: 238 case VolumeProjection_Sagittal:
245 for (unsigned int x = 0; x < width_; x++) 239 for (unsigned int x = 0; x < width_; x++)
246 { 240 {
247 Vector origin = axialGeometry_.GetOrigin(); 241 Vector origin = axialGeometry_.GetOrigin();
248 origin += static_cast<double>(x) * voxelDimensions_[0] * axialGeometry_.GetAxisX(); 242 origin += static_cast<double>(x) * voxelDimensions_[0] * axialGeometry_.GetAxisX();
249 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); 243 origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal();
250 244
251 result->AddSlice(origin, 245 result->AddSlice(origin,
252 axialGeometry_.GetAxisY(), 246 axialGeometry_.GetAxisY(),
253 -axialGeometry_.GetNormal()); 247 -axialGeometry_.GetNormal());
254 } 248 }
255 break; 249 break;
256 250
257 default: 251 default:
258 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 252 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
259 } 253 }
260 254
261 return result.release(); 255 return result.release();
262 } 256 }
263 257
264 258
265 uint64_t ImageBuffer3D::GetEstimatedMemorySize() const 259 uint64_t ImageBuffer3D::GetEstimatedMemorySize() const
266 { 260 {
267 return image_.GetPitch() * image_.GetHeight() * Orthanc::GetBytesPerPixel(format_); 261 return image_.GetPitch() * image_.GetHeight() * Orthanc::GetBytesPerPixel(format_);
268 } 262 }
276 { 270 {
277 return; 271 return;
278 } 272 }
279 273
280 float sliceMin, sliceMax; 274 float sliceMin, sliceMax;
281 275
282 switch (slice.GetFormat()) 276 switch (slice.GetFormat())
283 { 277 {
284 case Orthanc::PixelFormat_Grayscale8: 278 case Orthanc::PixelFormat_Grayscale8:
285 case Orthanc::PixelFormat_Grayscale16: 279 case Orthanc::PixelFormat_Grayscale16:
286 case Orthanc::PixelFormat_Grayscale32: 280 case Orthanc::PixelFormat_Grayscale32:
287 case Orthanc::PixelFormat_SignedGrayscale16: 281 case Orthanc::PixelFormat_SignedGrayscale16:
288 { 282 {
289 int64_t a, b; 283 int64_t a, b;
290 Orthanc::ImageProcessing::GetMinMaxIntegerValue(a, b, slice); 284 Orthanc::ImageProcessing::GetMinMaxIntegerValue(a, b, slice);
291 sliceMin = static_cast<float>(a); 285 sliceMin = static_cast<float>(a);
292 sliceMax = static_cast<float>(b); 286 sliceMax = static_cast<float>(b);
293 break; 287 break;
294 } 288 }
295 289
296 case Orthanc::PixelFormat_Float32: 290 case Orthanc::PixelFormat_Float32:
297 Orthanc::ImageProcessing::GetMinMaxFloatValue(sliceMin, sliceMax, slice); 291 Orthanc::ImageProcessing::GetMinMaxFloatValue(sliceMin, sliceMax, slice);
298 break; 292 break;
299 293
300 default: 294 default:
301 return; 295 return;
302 } 296 }
303 297
304 if (hasRange_) 298 if (hasRange_)
305 { 299 {
306 minValue_ = std::min(minValue_, sliceMin); 300 minValue_ = std::min(minValue_, sliceMin);
357 VolumeProjection projection, 351 VolumeProjection projection,
358 unsigned int slice) 352 unsigned int slice)
359 { 353 {
360 switch (projection) 354 switch (projection)
361 { 355 {
362 case VolumeProjection_Axial: 356 case VolumeProjection_Axial:
363 accessor_ = that.GetAxialSliceAccessor(slice, true); 357 that.GetAxialSliceAccessor(accessor_, slice, true);
364 break; 358 break;
365 359
366 case VolumeProjection_Coronal: 360 case VolumeProjection_Coronal:
367 accessor_ = that.GetCoronalSliceAccessor(slice, true); 361 that.GetCoronalSliceAccessor(accessor_, slice, true);
368 break; 362 break;
369 363
370 case VolumeProjection_Sagittal: 364 case VolumeProjection_Sagittal:
371 sagittal_.reset(that.ExtractSagittalSlice(slice)); 365 sagittal_.reset(that.ExtractSagittalSlice(slice));
372 accessor_ = *sagittal_; 366 sagittal_->GetReadOnlyAccessor(accessor_);
373 break; 367 break;
374 368
375 default: 369 default:
376 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 370 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
377 } 371 }
378 } 372 }
379 373
380 374
381 void ImageBuffer3D::SliceWriter::Flush() 375 void ImageBuffer3D::SliceWriter::Flush()
383 if (modified_) 377 if (modified_)
384 { 378 {
385 if (sagittal_.get() != NULL) 379 if (sagittal_.get() != NULL)
386 { 380 {
387 // TODO 381 // TODO
388 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 382 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
389 } 383 }
390 384
391 // Update the dynamic range of the underlying image, if 385 // Update the dynamic range of the underlying image, if
392 // "computeRange_" is set to true 386 // "computeRange_" is set to true
393 that_.ExtendImageRange(accessor_); 387 that_.ExtendImageRange(accessor_);
401 that_(that), 395 that_(that),
402 modified_(false) 396 modified_(false)
403 { 397 {
404 switch (projection) 398 switch (projection)
405 { 399 {
406 case VolumeProjection_Axial: 400 case VolumeProjection_Axial:
407 accessor_ = that.GetAxialSliceAccessor(slice, false); 401 that.GetAxialSliceAccessor(accessor_, slice, false);
408 break; 402 break;
409 403
410 case VolumeProjection_Coronal: 404 case VolumeProjection_Coronal:
411 accessor_ = that.GetCoronalSliceAccessor(slice, false); 405 that.GetCoronalSliceAccessor(accessor_, slice, false);
412 break; 406 break;
413 407
414 case VolumeProjection_Sagittal: 408 case VolumeProjection_Sagittal:
415 sagittal_.reset(that.ExtractSagittalSlice(slice)); 409 sagittal_.reset(that.ExtractSagittalSlice(slice));
416 accessor_ = *sagittal_; 410 sagittal_->GetWriteableAccessor(accessor_);
417 break; 411 break;
418 412
419 default: 413 default:
420 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 414 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
421 } 415 }
422 } 416 }
423 417
424 418
425 uint8_t ImageBuffer3D::GetVoxelGrayscale8(unsigned int x, 419 uint8_t ImageBuffer3D::GetVoxelGrayscale8(unsigned int x,
471 Vector ps = GetVoxelDimensions(OrthancStone::VolumeProjection_Axial); 465 Vector ps = GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
472 466
473 const CoordinateSystem3D& axial = GetAxialGeometry(); 467 const CoordinateSystem3D& axial = GetAxialGeometry();
474 468
475 Vector origin = (axial.MapSliceToWorldCoordinates(-0.5 * ps[0], -0.5 * ps[1]) - 469 Vector origin = (axial.MapSliceToWorldCoordinates(-0.5 * ps[0], -0.5 * ps[1]) -
476 0.5 * ps[2] * axial.GetNormal()); 470 0.5 * ps[2] * axial.GetNormal());
477 471
478 return (origin + 472 return (origin +
479 axial.GetAxisX() * ps[0] * x * static_cast<double>(GetWidth()) + 473 axial.GetAxisX() * ps[0] * x * static_cast<double>(GetWidth()) +
480 axial.GetAxisY() * ps[1] * y * static_cast<double>(GetHeight()) + 474 axial.GetAxisY() * ps[1] * y * static_cast<double>(GetHeight()) +
481 axial.GetNormal() * ps[2] * z * static_cast<double>(GetDepth())); 475 axial.GetNormal() * ps[2] * z * static_cast<double>(GetDepth()));
482 } 476 }
483 } 477 }