CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxImageParameters.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 #include "cxImageParameters.h"
12 #include "cxLogger.h"
13 #include "cxTypeConversions.h"
14 
15 namespace cx
16 {
18  mDim(Eigen::Array3i(0,0,0)),
19  mSpacing(cx::Vector3D(1,1,1)),
20  mParentVolume(""),
21  m_rMd(cx::Transform3D::Identity())
22 {
23 }
24 
25 ImageParameters::ImageParameters(Eigen::Array3i dim, cx::Vector3D spacing, QString parent, cx::Transform3D rMd) :
26  mDim(dim),
27  mSpacing(spacing),
28  mParentVolume(parent),
29  m_rMd(rMd)
30 {
31 }
32 
33 Eigen::Array3i ImageParameters::getDim() const
34 {
35  return mDim;
36 }
37 
38 Eigen::Array3d ImageParameters::getSpacing() const
39 {
40  return mSpacing;
41 }
42 
44 {
45  return (mDim - 1).cast<double>() * mSpacing;
46 }
47 
49 {
50  return this->getBounds().prod();
51 }
52 
54 {
55  Eigen::Array3d dim = bounds / mSpacing;
56  mDim = round(dim).cast<int>();
57  mDim += 1;
58  this->alignSpacingKeepDim(bounds);
59 }
60 
61 void ImageParameters::alignSpacingKeepDim(Eigen::Array3d bounds)
62 {
63  for (unsigned i = 0; i < 3; ++i)
64  {
65  //Set spacing to 1 if one of the axes is degenerated
66  if((mDim[i] == 1) && similar(bounds[i], 0.0))
67  mSpacing[i] = 1;
68  else
69  mSpacing[i] = bounds[i] / double(mDim[i]-1);
70  }
71 }
72 
73 void ImageParameters::setSpacingKeepDim(Eigen::Array3d spacing)
74 {
75  mSpacing = spacing;
76 }
77 
78 void ImageParameters::setDimFromExtent(Eigen::Array3i extent)
79 {
80  mDim = extent + 1;
81 }
82 
87 void ImageParameters::limitVoxelsKeepBounds(unsigned long maxVoxels)
88 {
89  if (this->getNumVoxels() <= maxVoxels)
90  return;
91 
92  if(mDim.minCoeff() == 1) //At least one of the dimensions == 1
93  {
94  reportError("ImageParameters::limitVoxelsKeepBounds() only work with 3D images");
95  return;
96  }
97  // i: input spacing
98  // s: (output) spacing
99  // b: bounds
100  // e: extent
101  // d: dim
102  //
103  // Relations:
104  // e = d-1
105  // b = s*d
106  //
107  // Ve: The volume of the extent, i.e. volume in voxel space
108  // Ve = e0*e1*e2
109  // Ve = pow(pow(voxelCount,1/3)-1, 3) //convert from dim to extent
110  // Vb: The volume of the bounds, ie in physical space
111  // Vb = b0*b1*b2
112  //
113  // Start with the Extent volume:
114  // Ve = e0*e1*e2 = b0/s0 * b1/s1 * b2/s2 = Vb / (s0*s1*s2)
115  //
116  // Keep the ratios between the spacing components from the input spacing:
117  // f1 = i1/i0 = s1/s0
118  // f2 = i2/i0 = s2/s0
119  // This gives:
120  // s1 = f1*s0
121  // s2 = f2*s0
122  //
123  // Plug into extent volume:
124  // Ve = Vb / (s0^3*f1*f2)
125  // s0^3 = Vb/(Ve*f1*f2)
126  // s0 = pow(Vb/(Ve*f1*f2), 1/3)
127 
128  // init
129  Eigen::Array3d b = this->getBounds();
130  Eigen::Array3d i = this->getSpacing();
131  double f1 = i[1] / i[0];
132  double f2 = i[2] / i[0];
133  double Vb = b.prod();
134  double Ve = pow(pow(double(maxVoxels),1.0/3)-1, 3);
135 
136  // generate spacing array
137  Eigen::Array3d s;
138  s[0] = pow(Vb/(Ve*f1*f2), 1.0/3);
139  s[1] = f1 * s[0];
140  s[2] = f2 * s[0];
141 
142  // set values
143  mSpacing = s;
144  Eigen::Array3i e = (b/s).cast<int>();
145  // extents of 1 gives unstable results. extent 0 is an error.
146 // e = e.max(Eigen::Array3i(1,1,1));
147  this->setDimFromExtent(e);
148  this->alignSpacingKeepDim(b); // change spacing to keep bounds
149 }
150 
156 {
157  Eigen::Array3d b = this->getBounds();
158  double voxelCount = this->getNumVoxels();
159  double Vb = b.prod();
160  double Ve = pow(pow(double(voxelCount),1.0/3)-1, 3);
161  double spacing = pow(Vb/Ve, 1.0/3);
162  Eigen::Array3d s(spacing,spacing,spacing);
163 
164  // set values
165  mSpacing = Eigen::Array3d(spacing,spacing,spacing);
166  Eigen::Array3i e = (b/s).cast<int>();
167  this->setDimFromExtent(e);
168 }
169 
170 void ImageParameters::print(std::ostream& s, vtkIndent indent)
171 {
172  s << indent << "Dim: " << mDim << std::endl;
173  s << indent << "Spacing: " << mSpacing << std::endl;
174  s << indent << "Bounds: " << this->getBounds() << std::endl;
175  s << indent << "NumVoxels: " << this->getNumVoxels() << std::endl;
176  s << indent << "Parent Volume: " << mParentVolume << std::endl;
177  s << indent << "rMd:\n" << m_rMd << std::endl;
178 }
179 
180 
181 }// namespace cx
void reportError(QString msg)
Definition: cxLogger.cpp:71
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
void print(std::ostream &s, vtkIndent indent)
void limitVoxelsKeepBounds(unsigned long maxVolumeSize)
void setDimKeepBoundsAlignSpacing(Eigen::Array3d bounds)
Eigen::Array3i getDim() const
unsigned long getNumVoxels() const
Eigen::Array3d getBounds()
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:42
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
Eigen::Array3d getSpacing() const
Vector3D round(const Vector3D &a)
Definition: cxVector3D.cpp:75
void setSpacingKeepDim(Eigen::Array3d spacing)
Namespace for all CustusX production code.