Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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