comparison Framework/Volumes/ImageBuffer3D.cpp @ 683:dbc1d8bfc68a

reorganizing ImageBuffer3D
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 16 May 2019 16:01:36 +0200
parents e9339f2b5de7
children 7719eb852dd5
comparison
equal deleted inserted replaced
681:9723fceccb9f 683:dbc1d8bfc68a
19 **/ 19 **/
20 20
21 21
22 #include "ImageBuffer3D.h" 22 #include "ImageBuffer3D.h"
23 23
24 #include "../Toolbox/GeometryToolbox.h"
25
24 #include <Core/Images/ImageProcessing.h> 26 #include <Core/Images/ImageProcessing.h>
25 #include <Core/Logging.h> 27 #include <Core/Logging.h>
26 #include <Core/OrthancException.h> 28 #include <Core/OrthancException.h>
27 29
28 #include <string.h> 30 #include <string.h>
119 LinearAlgebra::AssignVector(voxelDimensions_, 1, 1, 1); 121 LinearAlgebra::AssignVector(voxelDimensions_, 1, 1, 1);
120 122
121 LOG(INFO) << "Created a 3D image of size " << width << "x" << height 123 LOG(INFO) << "Created a 3D image of size " << width << "x" << height
122 << "x" << depth << " in " << Orthanc::EnumerationToString(format) 124 << "x" << depth << " in " << Orthanc::EnumerationToString(format)
123 << " (" << (GetEstimatedMemorySize() / (1024ll * 1024ll)) << "MB)"; 125 << " (" << (GetEstimatedMemorySize() / (1024ll * 1024ll)) << "MB)";
126
127 UpdateGeometry();
124 } 128 }
125 129
126 130
127 void ImageBuffer3D::Clear() 131 void ImageBuffer3D::Clear()
128 { 132 {
131 135
132 136
133 void ImageBuffer3D::SetAxialGeometry(const CoordinateSystem3D& geometry) 137 void ImageBuffer3D::SetAxialGeometry(const CoordinateSystem3D& geometry)
134 { 138 {
135 axialGeometry_ = geometry; 139 axialGeometry_ = geometry;
140 UpdateGeometry();
136 } 141 }
137 142
138 143
139 void ImageBuffer3D::SetVoxelDimensions(double x, 144 void ImageBuffer3D::SetVoxelDimensions(double x,
140 double y, 145 double y,
144 y <= 0 || 149 y <= 0 ||
145 z <= 0) 150 z <= 0)
146 { 151 {
147 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 152 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
148 } 153 }
149 154 else
150 { 155 {
151 LinearAlgebra::AssignVector(voxelDimensions_, x, y, z); 156 LinearAlgebra::AssignVector(voxelDimensions_, x, y, z);
157 UpdateGeometry();
152 } 158 }
153 } 159 }
154 160
155 161
156 Vector ImageBuffer3D::GetVoxelDimensions(VolumeProjection projection) const 162 Vector ImageBuffer3D::GetVoxelDimensions(VolumeProjection projection) const
157 { 163 {
158 Vector result;
159 switch (projection) 164 switch (projection)
160 { 165 {
161 case VolumeProjection_Axial: 166 case VolumeProjection_Axial:
162 result = voxelDimensions_; 167 return voxelDimensions_;
163 break;
164 168
165 case VolumeProjection_Coronal: 169 case VolumeProjection_Coronal:
166 LinearAlgebra::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]); 170 return LinearAlgebra::CreateVector(voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]);
167 break;
168 171
169 case VolumeProjection_Sagittal: 172 case VolumeProjection_Sagittal:
170 LinearAlgebra::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]); 173 return LinearAlgebra::CreateVector(voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]);
171 break;
172 174
173 default: 175 default:
174 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 176 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
175 } 177 }
176
177 return result;
178 } 178 }
179 179
180 180
181 void ImageBuffer3D::GetSliceSize(unsigned int& width, 181 void ImageBuffer3D::GetSliceSize(unsigned int& width,
182 unsigned int& height, 182 unsigned int& height,
457 const void* p = image_.GetConstRow(y + height_ * (depth_ - 1 - z)); 457 const void* p = image_.GetConstRow(y + height_ * (depth_ - 1 - z));
458 return reinterpret_cast<const uint16_t*>(p) [x]; 458 return reinterpret_cast<const uint16_t*>(p) [x];
459 } 459 }
460 460
461 461
462 void ImageBuffer3D::UpdateGeometry()
463 {
464 Vector p = (axialGeometry_.GetOrigin() +
465 static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal());
466
467 coronalGeometry_ = CoordinateSystem3D(p,
468 axialGeometry_.GetAxisX(),
469 -axialGeometry_.GetNormal());
470
471 sagittalGeometry_ = CoordinateSystem3D(p,
472 axialGeometry_.GetAxisY(),
473 -axialGeometry_.GetNormal());
474
475 Vector origin = (
476 axialGeometry_.MapSliceToWorldCoordinates(-0.5 * voxelDimensions_[0],
477 -0.5 * voxelDimensions_[1]) -
478 0.5 * voxelDimensions_[2] * axialGeometry_.GetNormal());
479
480 Vector scaling = (
481 axialGeometry_.GetAxisX() * voxelDimensions_[0] * static_cast<double>(width_) +
482 axialGeometry_.GetAxisY() * voxelDimensions_[1] * static_cast<double>(height_) +
483 axialGeometry_.GetNormal() * voxelDimensions_[2] * static_cast<double>(depth_));
484
485 transform_ = LinearAlgebra::Product(
486 GeometryToolbox::CreateTranslationMatrix(origin[0], origin[1], origin[2]),
487 GeometryToolbox::CreateScalingMatrix(scaling[0], scaling[1], scaling[2]));
488
489 LinearAlgebra::InvertMatrix(transformInverse_, transform_);
490 }
491
492
462 Vector ImageBuffer3D::GetCoordinates(float x, 493 Vector ImageBuffer3D::GetCoordinates(float x,
463 float y, 494 float y,
464 float z) const 495 float z) const
465 { 496 {
466 Vector ps = GetVoxelDimensions(OrthancStone::VolumeProjection_Axial); 497 Vector p = LinearAlgebra::Product(transform_, LinearAlgebra::CreateVector(x, y, z, 1));
467 498
468 const CoordinateSystem3D& axial = GetAxialGeometry(); 499 assert(LinearAlgebra::IsNear(p[3], 1)); // Affine transform, no perspective effect
469 500
470 Vector origin = (axial.MapSliceToWorldCoordinates(-0.5 * ps[0], -0.5 * ps[1]) - 501 // Back to non-homogeneous coordinates
471 0.5 * ps[2] * axial.GetNormal()); 502 return LinearAlgebra::CreateVector(p[0], p[1], p[2]);
472 503 }
473 return (origin + 504
474 axial.GetAxisX() * ps[0] * x * static_cast<double>(GetWidth()) + 505
475 axial.GetAxisY() * ps[1] * y * static_cast<double>(GetHeight()) + 506 bool ImageBuffer3D::DetectProjection(VolumeProjection& projection,
476 axial.GetNormal() * ps[2] * z * static_cast<double>(GetDepth())); 507 const CoordinateSystem3D& plane) const
508 {
509 if (GeometryToolbox::IsParallel(plane.GetNormal(),
510 axialGeometry_.GetNormal()))
511 {
512 projection = VolumeProjection_Axial;
513 return true;
514 }
515
516 {
517 if (GeometryToolbox::IsParallel(plane.GetNormal(),
518 coronalGeometry_.GetNormal()))
519 {
520 projection = VolumeProjection_Coronal;
521 return true;
522 }
523 }
524
525 {
526 if (GeometryToolbox::IsParallel(plane.GetNormal(),
527 sagittalGeometry_.GetNormal()))
528 {
529 projection = VolumeProjection_Sagittal;
530 return true;
531 }
532 }
533
534 return false;
477 } 535 }
478 } 536 }