Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkPlaneProposer.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkPlaneProposer.h"
14 
15 #include <mitkGeometryData.h>
16 #include <mitkPlaneFit.h>
17 #include <mitkPointSet.h>
19 #include <mitkUnstructuredGrid.h>
20 #include <mitkVector.h>
21 
22 #include <vtkCenterOfMass.h>
23 #include <vtkDoubleArray.h>
24 #include <vtkMath.h>
25 #include <vtkPointData.h>
26 #include <vtkSmartPointer.h>
27 #include <vtkUnstructuredGrid.h>
28 
29 bool compare(std::pair<double, int> i, std::pair<double, int> j)
30 {
31  return (i.first > j.first);
32 }
33 
34 mitk::PlaneProposer::PlaneProposer() : m_UseDistances(false), m_UseLeastSquares(false), m_NumberOfClustersToUse(3)
35 {
36 }
37 
39 {
40 }
41 
42 void mitk::PlaneProposer::SetUnstructuredGrids(std::vector<mitk::UnstructuredGrid::Pointer> &grids)
43 {
44  if (grids.empty())
45  {
46  MITK_WARN << "Input grids are empty!";
47  return;
48  }
49  m_Grids = grids;
50 }
51 
53 {
54  m_UseDistances = status;
55 }
56 
58 {
59  m_NumberOfClustersToUse = num;
60 }
61 
63 {
64  m_SNC = snc;
65 }
66 
67 std::array<std::array<double, 3>, 3> mitk::PlaneProposer::GetCentroids()
68 {
69  return m_Centroids;
70 }
71 
73 {
74  return m_ProposedPlaneInfo;
75 }
76 
78 {
79  // find the avg distances of every cluster maybe a square mean for better looking at high values?
80  std::vector<std::pair<double, int>> avgDistances;
81 
82  // get the number of points and the id of every cluster
83  std::vector<std::pair<int, int>> sizeIDs;
84 
85  for (unsigned int i = 0; i < m_Grids.size(); i++)
86  {
87  mitk::UnstructuredGrid::Pointer cluster = m_Grids.at(i);
88  vtkSmartPointer<vtkDoubleArray> data =
89  dynamic_cast<vtkDoubleArray *>(cluster->GetVtkUnstructuredGrid()->GetPointData()->GetArray(0));
90  double avg = 0.0;
91  for (int j = 0; j < data->GetSize(); j++)
92  {
93  avg += data->GetValue(j);
94  }
95  avgDistances.push_back(std::make_pair(avg / static_cast<double>(data->GetSize()), i));
96  }
97 
98  // now sort the clusters with their distances
99  for (unsigned int i = 0; i < m_Grids.size(); i++)
100  {
101  sizeIDs.push_back(std::make_pair(m_Grids.at(i)->GetVtkUnstructuredGrid()->GetNumberOfPoints(), i));
102  }
103 
104  // sort the point IDs for finding the biggest clusters and clusters with the
105  // highest distance
106  // sizeIDs is sorted by number of points in each cluster
107  // avgDistances is sorted by avg distance to next edge
108  std::sort(sizeIDs.begin(), sizeIDs.end(), compare);
109  std::sort(avgDistances.begin(), avgDistances.end(), compare);
110 
111  if (m_Grids.size() < m_NumberOfClustersToUse || m_UseLeastSquares)
112  {
113  // We need at least three points to define a plane
114  m_NumberOfClustersToUse = m_Grids.size();
115  m_ProposedPlaneInfo = this->CreatePlaneByLeastSquares(sizeIDs, avgDistances);
116  }
117  else
118  {
119  m_ProposedPlaneInfo = this->CreatePlaneByCentroids(sizeIDs, avgDistances);
120  }
121 
122  if (m_SNC.IsNotNull())
123  {
124  m_SNC->ReorientSlices(m_SNC->GetCurrentPlaneGeometry()->GetCenter(), m_ProposedPlaneInfo.x, m_ProposedPlaneInfo.y);
125  m_SNC->SelectSliceByPoint(m_ProposedPlaneInfo.pointOnPlane);
126  }
127 }
128 
129 mitk::PlaneProposer::PlaneInfo mitk::PlaneProposer::CreatePlaneByCentroids(
130  const std::vector<std::pair<int, int>> &sizeIDs, const std::vector<std::pair<double, int>> &avgDistances)
131 {
132  for (unsigned int j = 0; j < m_NumberOfClustersToUse; j++) // iterate over the clusters
133  {
134  // Get the cluster with "id" from all clusters, "id" is saved in sizeIDs.second
135  // sizeIDs.first represent the number of points which is only needed for sorting the "id"s
136  vtkSmartPointer<vtkUnstructuredGrid> tmpGrid;
137 
138  if (m_UseDistances)
139  tmpGrid = m_Grids.at(avgDistances.at(j).second)->GetVtkUnstructuredGrid(); // highest distance
140  else
141  tmpGrid = m_Grids.at(sizeIDs.at(j).second)->GetVtkUnstructuredGrid(); // biggest cluster
142 
143  double tmpCenter[3];
144  vtkCenterOfMass::ComputeCenterOfMass(tmpGrid->GetPoints(), nullptr, tmpCenter);
145  std::array<double, 3> center;
146  center[0] = tmpCenter[0];
147  center[1] = tmpCenter[1];
148  center[2] = tmpCenter[2];
149  m_Centroids[j] = center;
150  }
151 
152  double x[3];
153  x[0] = m_Centroids[1][0] - m_Centroids[0][0];
154  x[1] = m_Centroids[1][1] - m_Centroids[0][1];
155  x[2] = m_Centroids[1][2] - m_Centroids[0][2];
156  double y[3];
157  y[0] = m_Centroids[2][0] - m_Centroids[0][0];
158  y[1] = m_Centroids[2][1] - m_Centroids[0][1];
159  y[2] = m_Centroids[2][2] - m_Centroids[0][2];
160  double normal[3];
161  vtkMath::Cross(x, y, normal); // TODO do it manually!
163  planeInfo.normal = normal;
164  planeInfo.x = x;
165  planeInfo.y = y;
166  planeInfo.pointOnPlane[0] = m_Centroids[0][0];
167  planeInfo.pointOnPlane[1] = m_Centroids[0][1];
168  planeInfo.pointOnPlane[2] = m_Centroids[0][2];
169  return planeInfo;
170 }
171 
172 mitk::PlaneProposer::PlaneInfo mitk::PlaneProposer::CreatePlaneByLeastSquares(
173  const std::vector<std::pair<int, int>> &sizeIDs, const std::vector<std::pair<double, int>> &avgDistances)
174 {
175  // Generate a pointset from UnstructuredGrid for the PlaneFitFilter:
177 
178  int pointId = 0;
179 
180  for (unsigned int j = 0; j < m_NumberOfClustersToUse; j++) // iterate over the clusters
181  {
182  // Get the cluster with "id" from all clusters, "id" is saved in sizeIDs.second
183  // sizeIDs.first represent the number of points which is only needed for sorting the "id"s
184  vtkSmartPointer<vtkUnstructuredGrid> tmpGrid;
185 
186  if (m_UseDistances)
187  tmpGrid = m_Grids.at(avgDistances.at(j).second)->GetVtkUnstructuredGrid(); // highest distance
188  else
189  tmpGrid = m_Grids.at(sizeIDs.at(j).second)->GetVtkUnstructuredGrid(); // biggest cluster
190 
191  for (int i = 0; i < tmpGrid->GetNumberOfPoints(); i++)
192  {
193  mitk::Point3D point;
194  point[0] = tmpGrid->GetPoint(i)[0];
195  point[1] = tmpGrid->GetPoint(i)[1];
196  point[2] = tmpGrid->GetPoint(i)[2];
197 
198  pointset->InsertPoint(pointId, point);
199  pointId++;
200  }
201  }
203  planeFilter->SetInput(pointset);
204  planeFilter->Update();
205 
206  mitk::GeometryData::Pointer geoData = planeFilter->GetOutput();
207 
208  if (geoData.IsNull())
209  {
210  mitkThrow() << "GeometryData output from PlaneFit filter is null!";
211  }
213  mitk::PlaneGeometry::Pointer plane = dynamic_cast<mitk::PlaneGeometry *>(geoData->GetGeometry());
214  planeInfo.normal = plane->GetNormal();
215  planeInfo.pointOnPlane = plane->GetCenter();
216  return planeInfo;
217 }
static Pointer New()
void SetUseDistances(bool)
If true, the three clusters with the biggest mean distances are used for plane proposal Required the ...
#define MITK_WARN
Definition: mitkLogMacros.h:19
bool compare(std::pair< double, int > i, std::pair< double, int > j)
Encapsulates the geometrical information needed to descripe a PlaneInfo.
void CreatePlaneInfo()
Creates the actual plane proposal.
#define mitkThrow()
void SetNumberOfClustersToUse(unsigned int)
Sets the number of the clusters to be used for plane creation (default=3)
void SetSliceNavigationController(itk::SmartPointer< mitk::SliceNavigationController > &snc)
PlaneInfo GetProposedPlaneInfo()
static Pointer New()
Describes a two-dimensional, rectangular plane.
std::array< std::array< double, 3 >, 3 > GetCentroids()
void SetUnstructuredGrids(std::vector< itk::SmartPointer< mitk::UnstructuredGrid >> &grids)