Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkParticleGrid.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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 
18 #include "mitkParticleGrid.h"
19 #include <stdlib.h>
20 #include <stdio.h>
21 
22 using namespace mitk;
23 
24 ParticleGrid::ParticleGrid(ItkFloatImageType* image, float particleLength, int cellCapacity)
25 {
26  // initialize counters
27  m_NumParticles = 0;
28  m_NumConnections = 0;
30  m_ParticleLength = particleLength;
31 
32  // define isotropic grid from voxel spacing and particle length
33  float cellSize = 2*m_ParticleLength;
34  m_GridSize[0] = image->GetLargestPossibleRegion().GetSize()[0]*image->GetSpacing()[0]/cellSize +1;
35  m_GridSize[1] = image->GetLargestPossibleRegion().GetSize()[1]*image->GetSpacing()[1]/cellSize +1;
36  m_GridSize[2] = image->GetLargestPossibleRegion().GetSize()[2]*image->GetSpacing()[2]/cellSize +1;
37  m_GridScale[0] = 1/cellSize;
38  m_GridScale[1] = 1/cellSize;
39  m_GridScale[2] = 1/cellSize;
40 
41  m_CellCapacity = cellCapacity; // maximum number of particles per grid cell
42  m_ContainerCapacity = 100000; // initial particle container capacity
43  unsigned long numCells = m_GridSize[0]*m_GridSize[1]*m_GridSize[2]; // number of grid cells
44  unsigned long gridSize = numCells*m_CellCapacity;
45  if ( (unsigned long)itk::NumericTraits<int>::max()<gridSize )
46  throw std::bad_alloc();
47 
48  m_Particles.resize(m_ContainerCapacity); // allocate and initialize particles
49  m_Grid.resize(gridSize, nullptr); // allocate and initialize particle grid
50  m_OccupationCount.resize(numCells, 0); // allocate and initialize occupation counter array
51  m_NeighbourTracker.cellidx.resize(8, 0); // allocate and initialize neighbour tracker
52  m_NeighbourTracker.cellidx_c.resize(8, 0);
53 
54  for (int i = 0;i < m_ContainerCapacity;i++) // initialize particle IDs
55  m_Particles[i].ID = i;
56 
57  std::cout << "ParticleGrid: allocated " << (sizeof(Particle)*m_ContainerCapacity + sizeof(Particle*)*m_GridSize[0]*m_GridSize[1]*m_GridSize[2])/1048576 << "mb for " << m_ContainerCapacity/1000 << "k particles." << std::endl;
58 }
59 
61 {
62 
63 }
64 
65 // remove all particles
67 {
68  // initialize counters
69  m_NumParticles = 0;
70  m_NumConnections = 0;
72  m_Particles.clear();
73  m_Grid.clear();
74  m_OccupationCount.clear();
77 
78  int numCells = m_GridSize[0]*m_GridSize[1]*m_GridSize[2]; // number of grid cells
79 
80  m_Particles.resize(m_ContainerCapacity); // allocate and initialize particles
81  m_Grid.resize(numCells*m_CellCapacity, nullptr); // allocate and initialize particle grid
82  m_OccupationCount.resize(numCells, 0); // allocate and initialize occupation counter array
83  m_NeighbourTracker.cellidx.resize(8, 0); // allocate and initialize neighbour tracker
84  m_NeighbourTracker.cellidx_c.resize(8, 0);
85 
86  for (int i = 0;i < m_ContainerCapacity;i++) // initialize particle IDs
87  m_Particles[i].ID = i;
88 }
89 
91 {
92  int new_capacity = m_ContainerCapacity + 100000; // increase container capacity by 100k particles
93  try
94  {
95  m_Particles.resize(new_capacity); // reallocate particles
96 
97  for (int i = 0; i<m_ContainerCapacity; i++) // update particle addresses (changed during reallocation)
98  m_Grid[m_Particles[i].gridindex] = &m_Particles[i];
99 
100  for (int i = m_ContainerCapacity; i < new_capacity; i++) // initialize IDs of ne particles
101  m_Particles[i].ID = i;
102 
103  m_ContainerCapacity = new_capacity; // update member variable
104  //std::cout << "ParticleGrid: allocated " << (sizeof(Particle)*m_ContainerCapacity + sizeof(Particle*)*m_GridSize[0]*m_GridSize[1]*m_GridSize[2])/1048576 << "mb for " << m_ContainerCapacity/1000 << "k particles." << std::endl;
105  }
106  catch(...)
107  {
108  std::cout << "ParticleGrid: allocation of " << (sizeof(Particle)*new_capacity + sizeof(Particle*)*m_GridSize[0]*m_GridSize[1]*m_GridSize[2])/1048576 << "mb for " << new_capacity/1000 << "k particles failed!" << std::endl;
109  return false;
110  }
111  return true;
112 }
113 
115 {
116  if (ID!=-1)
117  return &m_Particles[ID];
118  return nullptr;
119 }
120 
121 
122 Particle* ParticleGrid::NewParticle(vnl_vector_fixed<float, 3> R)
123 {
125  {
126  if (!ReallocateGrid())
127  return nullptr;
128  }
129 
130  int xint = int(R[0]*m_GridScale[0]);
131  if (xint < 0)
132  return nullptr;
133  if (xint >= m_GridSize[0])
134  return nullptr;
135  int yint = int(R[1]*m_GridScale[1]);
136  if (yint < 0)
137  return nullptr;
138  if (yint >= m_GridSize[1])
139  return nullptr;
140  int zint = int(R[2]*m_GridScale[2]);
141  if (zint < 0)
142  return nullptr;
143  if (zint >= m_GridSize[2])
144  return nullptr;
145 
146  int idx = xint + m_GridSize[0]*(yint + m_GridSize[1]*zint);
148  {
150  p->GetPos() = R;
151  p->mID = -1;
152  p->pID = -1;
153  m_NumParticles++;
155  m_Grid[p->gridindex] = p;
156  m_OccupationCount[idx]++;
157  return p;
158  }
159  else
160  {
162  return nullptr;
163  }
164 }
165 
167 {
168  Particle* p = &(m_Particles[k]);
169 
170  int xint = int(p->GetPos()[0]*m_GridScale[0]);
171  if (xint < 0)
172  return false;
173  if (xint >= m_GridSize[0])
174  return false;
175  int yint = int(p->GetPos()[1]*m_GridScale[1]);
176  if (yint < 0)
177  return false;
178  if (yint >= m_GridSize[1])
179  return false;
180  int zint = int(p->GetPos()[2]*m_GridScale[2]);
181  if (zint < 0)
182  return false;
183  if (zint >= m_GridSize[2])
184  return false;
185 
186  int idx = xint + m_GridSize[0]*(yint+ zint*m_GridSize[1]);
187  int cellidx = p->gridindex/m_CellCapacity;
188  if (idx != cellidx) // cell has changed
189  {
190 
192  {
193  // remove from old position in grid;
194  int grdindex = p->gridindex;
195  m_Grid[grdindex] = m_Grid[cellidx*m_CellCapacity + m_OccupationCount[cellidx]-1];
196  m_Grid[grdindex]->gridindex = grdindex;
197  m_OccupationCount[cellidx]--;
198 
199  // insert at new position in grid
200  p->gridindex = idx*m_CellCapacity + m_OccupationCount[idx];
201  m_Grid[p->gridindex] = p;
202  m_OccupationCount[idx]++;
203  return true;
204  }
205  else
206  {
208  return false;
209  }
210  }
211  return true;
212 }
213 
215 {
216  Particle* p = &(m_Particles[k]);
217  int gridIndex = p->gridindex;
218  int cellIdx = gridIndex/m_CellCapacity;
219  int idx = gridIndex%m_CellCapacity;
220 
221  // remove pending connections
222  if (p->mID != -1)
223  DestroyConnection(p,-1);
224  if (p->pID != -1)
225  DestroyConnection(p,+1);
226 
227  // remove from grid
228  if (idx < m_OccupationCount[cellIdx]-1)
229  {
230  m_Grid[gridIndex] = m_Grid[cellIdx*m_CellCapacity+m_OccupationCount[cellIdx]-1];
231  m_Grid[cellIdx*m_CellCapacity+m_OccupationCount[cellIdx]-1] = nullptr;
232  m_Grid[gridIndex]->gridindex = gridIndex;
233  }
234  m_OccupationCount[cellIdx]--;
235 
236  // remove from container
237  if (k < m_NumParticles-1)
238  {
239  Particle* last = &m_Particles[m_NumParticles-1]; // last particle
240 
241  // update connections of last particle because its index is changing
242  if (last->mID!=-1)
243  {
244  if ( m_Particles[last->mID].mID == m_NumParticles-1 )
245  m_Particles[last->mID].mID = k;
246  else if ( m_Particles[last->mID].pID == m_NumParticles-1 )
247  m_Particles[last->mID].pID = k;
248  }
249  if (last->pID!=-1)
250  {
251  if ( m_Particles[last->pID].mID == m_NumParticles-1 )
252  m_Particles[last->pID].mID = k;
253  else if ( m_Particles[last->pID].pID == m_NumParticles-1 )
254  m_Particles[last->pID].pID = k;
255  }
256 
257  m_Particles[k] = m_Particles[m_NumParticles-1]; // move very last particle to empty slot
258  m_Particles[m_NumParticles-1].ID = m_NumParticles-1; // update ID of removed particle to match the index
259  m_Particles[k].ID = k; // update ID of moved particle
260  m_Grid[m_Particles[k].gridindex] = &m_Particles[k]; // update address of moved particle
261  }
262  m_NumParticles--;
263 }
264 
265 void ParticleGrid::ComputeNeighbors(vnl_vector_fixed<float, 3> &R)
266 {
267  float xfrac = R[0]*m_GridScale[0];
268  float yfrac = R[1]*m_GridScale[1];
269  float zfrac = R[2]*m_GridScale[2];
270  int xint = int(xfrac);
271  int yint = int(yfrac);
272  int zint = int(zfrac);
273 
274  int dx = -1;
275  if (xfrac-xint > 0.5) dx = 1;
276  if (xint <= 0) { xint = 0; dx = 1; }
277  if (xint >= m_GridSize[0]-1) { xint = m_GridSize[0]-1; dx = -1; }
278  if (m_GridSize[0] <= 1) { dx = 0; } // Necessary with 2d images (bug 15416)
279 
280  int dy = -1;
281  if (yfrac-yint > 0.5) dy = 1;
282  if (yint <= 0) {yint = 0; dy = 1; }
283  if (yint >= m_GridSize[1]-1) {yint = m_GridSize[1]-1; dy = -1;}
284  if (m_GridSize[1] <= 1) { dy = 0; } // Necessary with 2d images (bug 15416)
285 
286  int dz = -1;
287  if (zfrac-zint > 0.5) dz = 1;
288  if (zint <= 0) {zint = 0; dz = 1; }
289  if (zint >= m_GridSize[2]-1) {zint = m_GridSize[2]-1; dz = -1;}
290  if (m_GridSize[2] <= 1) { dz = 0; } // Necessary with 2d images (bug 15416)
291 
292 
293  m_NeighbourTracker.cellidx[0] = xint + m_GridSize[0]*(yint+zint*m_GridSize[1]);
297  m_NeighbourTracker.cellidx[4] = m_NeighbourTracker.cellidx[0] + dz*m_GridSize[0]*m_GridSize[1];
299  m_NeighbourTracker.cellidx[6] = m_NeighbourTracker.cellidx[5] + dy*m_GridSize[0];
301 
302 
311 
314 }
315 
317 {
319  {
321  }
322  else
323  {
324  for(;;)
325  {
327  if (m_NeighbourTracker.cellcnt >= 8)
328  return nullptr;
330  break;
331  }
334  }
335 }
336 
337 void ParticleGrid::CreateConnection(Particle *P1,int ep1, Particle *P2, int ep2)
338 {
339  if (ep1 == -1)
340  P1->mID = P2->ID;
341  else
342  P1->pID = P2->ID;
343 
344  if (ep2 == -1)
345  P2->mID = P1->ID;
346  else
347  P2->pID = P1->ID;
348 
350 }
351 
352 void ParticleGrid::DestroyConnection(Particle *P1,int ep1, Particle *P2, int ep2)
353 {
354  if (ep1 == -1)
355  P1->mID = -1;
356  else
357  P1->pID = -1;
358 
359  if (ep2 == -1)
360  P2->mID = -1;
361  else
362  P2->pID = -1;
364 }
365 
367 {
368 
369  Particle *P2 = nullptr;
370  if (ep1 == 1)
371  {
372  P2 = &m_Particles[P1->pID];
373  P1->pID = -1;
374  }
375  else
376  {
377  P2 = &m_Particles[P1->mID];
378  P1->mID = -1;
379  }
380 
381  if (P2->mID == P1->ID)
382  P2->mID = -1;
383  else
384  P2->pID = -1;
385 
387 }
388 
390 {
391  for (int i=0; i<m_NumParticles; i++)
392  {
393  Particle* p = &m_Particles[i];
394  if (p->ID != i)
395  {
396  std::cout << "Particle ID error!" << std::endl;
397  return false;
398  }
399 
400  if (p->mID!=-1)
401  {
402  Particle* p2 = &m_Particles[p->mID];
403  if (p2->mID!=p->ID && p2->pID!=p->ID)
404  {
405  std::cout << "Connection inconsistent!" << std::endl;
406  return false;
407  }
408  }
409  if (p->pID!=-1)
410  {
411  Particle* p2 = &m_Particles[p->pID];
412  if (p2->mID!=p->ID && p2->pID!=p->ID)
413  {
414  std::cout << "Connection inconsistent!" << std::endl;
415  return false;
416  }
417  }
418  }
419  return true;
420 }
void CreateConnection(Particle *P1, int ep1, Particle *P2, int ep2)
A particle is the basic element of the Gibbs fiber tractography method.
Definition: mitkParticle.h:30
void ComputeNeighbors(vnl_vector_fixed< float, 3 > &R)
std::vector< Particle > m_Particles
DataCollection - Class to facilitate loading/accessing structured data.
vnl_vector_fixed< float, 3 > m_GridScale
ParticleGrid(ItkFloatImageType *image, float particleLength, int cellCapacity)
vnl_vector_fixed< float, 3 > & GetPos()
Definition: mitkParticle.h:51
Particle * GetParticle(int ID)
std::vector< int > m_OccupationCount
static T max(T x, T y)
Definition: svm.cpp:70
const std::string ID
void DestroyConnection(Particle *P1, int ep1, Particle *P2, int ep2)
vnl_vector_fixed< int, 3 > m_GridSize
std::vector< Particle * > m_Grid
Particle * GetNextNeighbor()
Particle * NewParticle(vnl_vector_fixed< float, 3 > R)
struct mitk::ParticleGrid::NeighborTracker m_NeighbourTracker
itk::Image< float, 3 > ItkFloatImageType