CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxImageEnveloper.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 
12 
13 #include "cxImageEnveloper.h"
14 #include "cxImage.h"
15 #include "cxVolumeHelpers.h"
16 #include "vtkImageData.h"
18 #include "cxTypeConversions.h"
19 #include "cxBoundingBox3D.h"
20 #include "cxImageTF3D.h"
21 
22 
23 namespace cx
24 {
26 {
27  return ImageEnveloperPtr(new ImageEnveloper());
28 }
29 
30 ImageEnveloper::ImageEnveloper() : mMaxEnvelopeVoxels(10*1000*1000)
31 {
32 
33 }
34 
36 {
37  mMaxEnvelopeVoxels = maxVoxels;
38 }
39 
40 void ImageEnveloper::setImages(std::vector<ImagePtr> images)
41 {
42  mImages = images;
43 }
44 
46 {
47  ImageParameters box = this->createEnvelopeParametersFromImage(mImages[0]);
48  for(unsigned i = 1; i < mImages.size(); ++i)
49  box = selectParametersWithSmallestExtent(box, this->createEnvelopeParametersFromImage(mImages[i]));
50 
51  box.limitVoxelsKeepBounds(mMaxEnvelopeVoxels);
52 
53  ImagePtr retval = this->createEnvelopeFromParameters(box);
54 
55  return retval;
56 }
57 
58 ImageParameters ImageEnveloper::createEnvelopeParametersFromImage(ImagePtr img)
59 {
60  ImageParameters retval;
61 
62  DoubleBoundingBox3D bb = findEnclosingBoundingBox(mImages, img->get_rMd().inverse());
63 
64  retval.setSpacingKeepDim(this->getMinimumSpacingFromAllImages(img->get_rMd().inverse()));
65  retval.setDimKeepBoundsAlignSpacing(bb.range().array());
66  retval.mParentVolume = img->getUid();
67 
68  Vector3D shift = bb.bottomLeft();
69 
70  retval.m_rMd = img->get_rMd() * createTransformTranslate(shift);
71 
72  return retval;
73 }
74 
75 ImageParameters ImageEnveloper::selectParametersWithSmallestExtent(ImageParameters a, ImageParameters b)
76 {
77  if (a.getVolume() <= b.getVolume())
78  return a;
79  else
80  return b;
81 }
82 
83 ImageParameters ImageEnveloper::selectParametersWithFewestVoxels(ImageParameters a, ImageParameters b)
84 {
85  if (a.getNumVoxels() <= b.getNumVoxels())
86  return a;
87  else
88  return b;
89 }
90 
91 Eigen::Array3d ImageEnveloper::getMinimumSpacingFromAllImages(Transform3D qMr)
92 {
93  Eigen::Array3d retval;
94  retval = this->getTransformedSpacing(mImages[0]->getSpacing(), qMr * mImages[0]->get_rMd());
95  for (unsigned i = 1; i < mImages.size(); ++i)
96  {
97  Eigen::Array3d current = this->getTransformedSpacing(mImages[i]->getSpacing(), qMr * mImages[i]->get_rMd());
98  retval = retval.min(current);
99  }
100  return retval;
101 }
102 
103 Eigen::Array3d ImageEnveloper::getTransformedSpacing(Eigen::Array3d spacing, Transform3D qMd)
104 {
105  Eigen::Array3d retval;
106 
107  //Create spacing vectors in img coord syst (d)
108  Vector3D sx = Vector3D(spacing[0], 0, 0);
109  Vector3D sy = Vector3D(0, spacing[1], 0);
110  Vector3D sz = Vector3D(0, 0, spacing[2]);
111 
112  //Transform to q coord syst
113  sx = qMd.vector(sx);
114  sy = qMd.vector(sy);
115  sz = qMd.vector(sz);
116 
117  //Find spacing for each axis
118  for (unsigned i = 0; i < 3; ++i)
119  {
120  retval[i] = std::max(fabs(sx[i]), fabs(sy[i]));
121  retval[i] = std::max(retval[i], fabs(sz[i]));
122  }
123 
124  return retval;
125 }
126 
127 ImagePtr ImageEnveloper::createEnvelopeFromParameters(ImageParameters box)
128 {
129  int maxRange = this->getMaxScalarRange();
130 
131  vtkImageDataPtr imageData = generateVtkImageDataUnsignedShort(box.getDim(), box.getSpacing(), maxRange, 1);
132 
133  QString uid = QString("envelope_image_%1").arg(box.mParentVolume);
134  ImagePtr retval(new Image(uid, imageData));
135  retval->get_rMd_History()->setRegistration(box.m_rMd);
136  retval->get_rMd_History()->setParentSpace(box.mParentVolume);
137  retval->setAcquisitionTime(QDateTime::currentDateTime());
138  retval->setModality(imSC);
139 
140  return retval;
141 }
142 
143 int ImageEnveloper::getMaxScalarRange()
144 {
145  int maxRange = 0;
146  for (unsigned i=0; i<mImages.size(); ++i)
147  maxRange = std::max<int>(maxRange, mImages[i]->getBaseVtkImageData()->GetScalarRange()[1]);
148  return maxRange;
149 }
150 
151 } // namespace cx
vtkImageDataPtr generateVtkImageDataUnsignedShort(Eigen::Array3i dim, Vector3D spacing, const unsigned short initValue, int components)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
Vector3D bottomLeft() const
static ImageEnveloperPtr create()
void limitVoxelsKeepBounds(unsigned long maxVolumeSize)
DoubleBoundingBox3D findEnclosingBoundingBox(std::vector< DataPtr > data, Transform3D qMr)
void setDimKeepBoundsAlignSpacing(Eigen::Array3d bounds)
imSC
Eigen::Array3i getDim() const
unsigned long getNumVoxels() const
A volumetric data set.
Definition: cxImage.h:45
Transform3D createTransformTranslate(const Vector3D &translation)
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
virtual void setImages(std::vector< ImagePtr > images)
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:42
Eigen::Array3d getSpacing() const
virtual ImagePtr getEnvelopingImage()
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
void setMaxEnvelopeVoxels(long maxVoxels)
boost::shared_ptr< class ImageEnveloper > ImageEnveloperPtr
void setSpacingKeepDim(Eigen::Array3d spacing)
Namespace for all CustusX production code.