Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkImageStatisticsTreeModel.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 
14 
16 #include "itkMutexLockHolder.h"
21 
23 {
24  m_RootItem = new QmitkImageStatisticsTreeItem();
25 }
26 
28 {
29  // set data storage to nullptr so that the event listener gets removed
30  this->SetDataStorage(nullptr);
31  delete m_RootItem;
32 };
33 
35 {
36  emit beginResetModel();
37  UpdateByDataStorage();
38  emit endResetModel();
39  emit modelChanged();
40 }
41 
43 {
44  emit beginResetModel();
45  UpdateByDataStorage();
46  emit endResetModel();
47  emit modelChanged();
48 }
49 
50 int QmitkImageStatisticsTreeModel::columnCount(const QModelIndex& /*parent*/) const
51 {
52  int columns = m_StatisticNames.size() + 1;
53  return columns;
54 }
55 
56 int QmitkImageStatisticsTreeModel::rowCount(const QModelIndex &parent) const
57 {
58  QmitkImageStatisticsTreeItem *parentItem;
59  if (parent.column() > 0)
60  return 0;
61 
62  if (!parent.isValid())
63  parentItem = m_RootItem;
64  else
65  parentItem = static_cast<QmitkImageStatisticsTreeItem *>(parent.internalPointer());
66 
67  return parentItem->childCount();
68 }
69 
70 QVariant QmitkImageStatisticsTreeModel::data(const QModelIndex &index, int role) const
71 {
72  if (!index.isValid())
73  return QVariant();
74 
75  if (role != Qt::DisplayRole)
76  return QVariant();
77 
78  QmitkImageStatisticsTreeItem *item = static_cast<QmitkImageStatisticsTreeItem *>(index.internalPointer());
79 
80  return item->data(index.column());
81 }
82 
83 QModelIndex QmitkImageStatisticsTreeModel::index(int row, int column, const QModelIndex &parent) const
84 {
85  if (!hasIndex(row, column, parent))
86  return QModelIndex();
87 
88  QmitkImageStatisticsTreeItem *parentItem;
89 
90  if (!parent.isValid())
91  parentItem = m_RootItem;
92  else
93  parentItem = static_cast<QmitkImageStatisticsTreeItem *>(parent.internalPointer());
94 
95  QmitkImageStatisticsTreeItem *childItem = parentItem->child(row);
96  if (childItem)
97  return createIndex(row, column, childItem);
98  else
99  return QModelIndex();
100 }
101 
102 QModelIndex QmitkImageStatisticsTreeModel::parent(const QModelIndex &child) const
103 {
104  if (!child.isValid())
105  return QModelIndex();
106 
107  QmitkImageStatisticsTreeItem *childItem = static_cast<QmitkImageStatisticsTreeItem *>(child.internalPointer());
108  QmitkImageStatisticsTreeItem *parentItem = childItem->parentItem();
109 
110  if (parentItem == m_RootItem)
111  return QModelIndex();
112 
113  return createIndex(parentItem->row(), 0, parentItem);
114 }
115 
116 Qt::ItemFlags QmitkImageStatisticsTreeModel::flags(const QModelIndex &index) const
117 {
118  if (!index.isValid())
119  return nullptr;
120 
121  return QAbstractItemModel::flags(index);
122 }
123 
124 QVariant QmitkImageStatisticsTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
125 {
126  if ((Qt::DisplayRole == role) && (Qt::Horizontal == orientation))
127  {
128  if (section == 0)
129  {
130  return m_HeaderFirstColumn;
131  }
132  else
133  {
134  return QVariant(m_StatisticNames.at(section - 1).c_str());
135  }
136  }
137  return QVariant();
138 }
139 
140 void QmitkImageStatisticsTreeModel::SetImageNodes(const std::vector<mitk::DataNode::ConstPointer> &nodes)
141 {
142  std::vector<std::pair<mitk::DataNode::ConstPointer, unsigned int>> tempNodes;
143  for (const auto &node : nodes)
144  {
145  auto data = node->GetData();
146  if (data)
147  {
148  auto timeSteps = data->GetTimeSteps();
149  for (unsigned int i = 0; i < timeSteps; i++)
150  {
151  tempNodes.push_back(std::make_pair(node, i));
152  }
153  }
154  }
155 
156  emit beginResetModel();
157  m_TimeStepResolvedImageNodes = std::move(tempNodes);
158  m_ImageNodes = nodes;
159  UpdateByDataStorage();
160  emit endResetModel();
161  emit modelChanged();
162 }
163 
164 void QmitkImageStatisticsTreeModel::SetMaskNodes(const std::vector<mitk::DataNode::ConstPointer> &nodes)
165 {
166  std::vector<std::pair<mitk::DataNode::ConstPointer, unsigned int>> tempNodes;
167  for (const auto &node : nodes)
168  {
169  auto data = node->GetData();
170  if (data)
171  {
172  auto timeSteps = data->GetTimeSteps();
173  // special case: apply one mask to each timestep of an 4D image
174  if (timeSteps == 1 && m_TimeStepResolvedImageNodes.size() > 1)
175  {
176  timeSteps = m_TimeStepResolvedImageNodes.size();
177  }
178  for (unsigned int i = 0; i < timeSteps; i++)
179  {
180  tempNodes.push_back(std::make_pair(node, i));
181  }
182  }
183  }
184 
185  emit beginResetModel();
186  m_TimeStepResolvedMaskNodes = std::move(tempNodes);
187  m_MaskNodes = nodes;
188  UpdateByDataStorage();
189  emit endResetModel();
190  emit modelChanged();
191 }
192 
194 {
195  emit beginResetModel();
196  m_Statistics.clear();
197  m_ImageNodes.clear();
198  m_TimeStepResolvedImageNodes.clear();
199  m_MaskNodes.clear();
200  m_StatisticNames.clear();
201  emit endResetModel();
202  emit modelChanged();
203 }
204 
205 void QmitkImageStatisticsTreeModel::UpdateByDataStorage()
206 {
207  StatisticsContainerVector newStatistics;
208 
209  auto datamanager = m_DataStorage.Lock();
210 
211  if (datamanager.IsNotNull())
212  {
213  for (const auto &image : m_ImageNodes)
214  {
215  if (m_MaskNodes.empty())
216  {
217  auto stats = mitk::ImageStatisticsContainerManager::GetImageStatistics(datamanager, image->GetData());
218 
219  if (stats.IsNotNull())
220  {
221  newStatistics.emplace_back(stats);
222  }
223  }
224  else
225  {
226  for (const auto &mask : m_MaskNodes)
227  {
228  auto stats =
229  mitk::ImageStatisticsContainerManager::GetImageStatistics(datamanager, image->GetData(), mask->GetData());
230  if (stats.IsNotNull())
231  {
232  newStatistics.emplace_back(stats);
233  }
234  }
235  }
236  }
237  if (!newStatistics.empty())
238  {
239  emit dataAvailable();
240  }
241  }
242 
243  {
245  m_Statistics = newStatistics;
246  }
247 
248  m_StatisticNames = mitk::GetAllStatisticNames(m_Statistics);
249  BuildHierarchicalModel();
250 }
251 
252 void QmitkImageStatisticsTreeModel::BuildHierarchicalModel()
253 {
254  // reset old model
255  delete m_RootItem;
256  m_RootItem = new QmitkImageStatisticsTreeItem();
257 
258  bool hasMask = false;
259  bool hasMultipleTimesteps = false;
260 
261  std::map<mitk::DataNode::ConstPointer, QmitkImageStatisticsTreeItem *> dataNodeToTreeItem;
262 
263  for (auto statistic : m_Statistics)
264  {
265  // get the connected image data node/mask data node
266  auto imageRule = mitk::StatisticsToImageRelationRule::New();
267  auto imageOfStatisticsPredicate = imageRule->GetDestinationsDetector(statistic);
268  auto imageFinding = std::find_if(m_ImageNodes.begin(), m_ImageNodes.end(), [&imageOfStatisticsPredicate](const mitk::DataNode::ConstPointer& testNode) { return imageOfStatisticsPredicate->CheckNode(testNode); });
269 
270  auto maskRule = mitk::StatisticsToMaskRelationRule::New();
271  auto maskOfStatisticsPredicate = maskRule->GetDestinationsDetector(statistic);
272  auto maskFinding = std::find_if(m_MaskNodes.begin(), m_MaskNodes.end(), [&maskOfStatisticsPredicate](const mitk::DataNode::ConstPointer& testNode) { return maskOfStatisticsPredicate->CheckNode(testNode); });
273 
274  if (imageFinding == m_ImageNodes.end())
275  {
276  mitkThrow() << "no image found connected to statistic" << statistic << " Aborting.";
277  }
278 
279  auto& image = *imageFinding;
280 
281  // image: 1. hierarchy level
282  QmitkImageStatisticsTreeItem *imageItem = nullptr;
283  auto search = dataNodeToTreeItem.find(image);
284  // the tree item was created previously
285  if (search != dataNodeToTreeItem.end())
286  {
287  imageItem = search->second;
288  }
289  // create the tree item
290  else
291  {
292  QString imageLabel = QString::fromStdString(image->GetName());
293  if (statistic->GetTimeSteps() == 1 && maskFinding == m_MaskNodes.end())
294  {
295  auto statisticsObject = statistic->GetStatisticsForTimeStep(0);
296  imageItem = new QmitkImageStatisticsTreeItem(statisticsObject, m_StatisticNames, imageLabel, m_RootItem);
297  }
298  else
299  {
300  imageItem = new QmitkImageStatisticsTreeItem(m_StatisticNames, imageLabel, m_RootItem);
301  }
302  m_RootItem->appendChild(imageItem);
303  dataNodeToTreeItem.emplace(image, imageItem);
304  }
305 
306  // mask: 2. hierarchy level (optional, only if mask exists)
307  QmitkImageStatisticsTreeItem *lastParent = nullptr;
308  if (maskFinding != m_MaskNodes.end())
309  {
310  auto& mask = *maskFinding;
311  QString maskLabel = QString::fromStdString(mask->GetName());
313  // add statistical values directly in this hierarchy level
314  if (statistic->GetTimeSteps() == 1)
315  {
316  auto statisticsObject = statistic->GetStatisticsForTimeStep(0);
317  maskItem = new QmitkImageStatisticsTreeItem(statisticsObject, m_StatisticNames, maskLabel, imageItem);
318  }
319  else
320  {
321  maskItem = new QmitkImageStatisticsTreeItem(m_StatisticNames, maskLabel, imageItem);
322  }
323 
324  imageItem->appendChild(maskItem);
325  lastParent = maskItem;
326  hasMask = true;
327  }
328  else
329  {
330  lastParent = imageItem;
331  }
332  // 3. hierarchy level (optional, only if >1 timestep)
333  if (statistic->GetTimeSteps() > 1)
334  {
335  for (unsigned int i = 0; i < statistic->GetTimeSteps(); i++)
336  {
337  QString timeStepLabel = "[" + QString::number(i) + "] " +
338  QString::number(statistic->GetTimeGeometry()->TimeStepToTimePoint(i)) + " ms";
339  if (statistic->TimeStepExists(i))
340  {
341  auto statisticsItem = new QmitkImageStatisticsTreeItem(
342  statistic->GetStatisticsForTimeStep(i), m_StatisticNames, timeStepLabel, lastParent);
343  lastParent->appendChild(statisticsItem);
344  }
345  }
346  hasMultipleTimesteps = true;
347  }
348  }
349  QString headerString = "Images";
350  if (hasMask)
351  {
352  headerString += "/Masks";
353  }
354  if (hasMultipleTimesteps)
355  {
356  headerString += "/Timesteps";
357  }
358  m_HeaderFirstColumn = headerString;
359 }
360 
362 {
363  emit beginResetModel();
364  UpdateByDataStorage();
365  emit endResetModel();
366  emit modelChanged();
367 }
368 
370 {
371  emit beginResetModel();
372  UpdateByDataStorage();
373  emit endResetModel();
374  emit modelChanged();
375 }
376 
378 {
379  emit beginResetModel();
380  UpdateByDataStorage();
381  emit endResetModel();
382  emit modelChanged();
383 }
itk::SmartPointer< T > Lock() const
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void SetDataStorage(mitk::DataStorage *dataStorage)
QmitkImageStatisticsTreeModel(QObject *parent=nullptr)
QmitkImageStatisticsTreeItem * parentItem()
QmitkImageStatisticsTreeItem * child(int row)
void NodeRemoved(const mitk::DataNode *node) override
void SetMaskNodes(const std::vector< mitk::DataNode::ConstPointer > &nodes)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex parent(const QModelIndex &child) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
void appendChild(QmitkImageStatisticsTreeItem *child)
void SetImageNodes(const std::vector< mitk::DataNode::ConstPointer > &nodes)
static mitk::ImageStatisticsContainer::ConstPointer GetImageStatistics(const mitk::DataStorage *dataStorage, const mitk::BaseData *image, const mitk::BaseData *mask=nullptr)
Returns the StatisticContainer for the given image and mask.
#define mitkThrow()
ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector GetAllStatisticNames(const ImageStatisticsContainer *container)
mitk::Image::Pointer image
void NodeChanged(const mitk::DataNode *node) override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
mitk::Image::Pointer mask
QVariant data(const QModelIndex &index, int role) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void NodeAdded(const mitk::DataNode *node) override
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
mitk::WeakPointer< mitk::DataStorage > m_DataStorage