Orfeo Toolbox  3.16
itkSharedMorphologyUtilities.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkSharedMorphologyUtilities.txx,v $
5  Language: C++
6  Date: $Date: 2009-10-29 15:03:32 $
7  Version: $Revision: 1.10 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 
18 #ifndef __itkSharedMorphologyUtilities_txx
19 #define __itkSharedMorphologyUtilities_txx
20 
25 #include <list>
26 
27 namespace itk {
28 
36 template <class TRegion, class TLine>
37 bool NeedToDoFace(const TRegion AllImage,
38  const TRegion face,
39  const TLine line)
40 {
41  // can't use the continuous IsInside (even if I could get it to
42  // work) because on the edge doesn't count as inside for this test
43 
44  // If the component of the vector orthogonal to the face doesn't go
45  // inside the image then we can ignore the face
46 
47  // find the small dimension of the face - should only be one
48  typename TRegion::IndexType ISt = AllImage.GetIndex();
49 
50  typename TRegion::SizeType FSz = face.GetSize();
51  typename TRegion::IndexType FSt = face.GetIndex();
52 
53  unsigned smallDim = 0;
54  for (unsigned i = 0; i < AllImage.GetImageDimension(); i++)
55  {
56  if (FSz[i] == 1)
57  {
58  smallDim = i;
59  break;
60  }
61  }
62  long startI = ISt[smallDim];
63  long facePos = FSt[smallDim] + FSz[smallDim] - 1;
64  if (facePos == startI)
65  {
66  // at the start of dimension - vector must be positive
67  if (line[smallDim] > 0.000001) return true;
68  // some small angle that we consider to be zero - should be more rigorous
69  }
70  else
71  {
72  // at the end of dimension - vector must be positive
73  if (line[smallDim] < -0.000001) return true;
74  }
75  return (false);
76 
77 }
78 template <class TImage, class TBres, class TLine>
79 int ComputeStartEnd(const typename TImage::IndexType StartIndex,
80  const TLine line,
81  const float tol,
82  const typename TBres::OffsetArray LineOffsets,
83  const typename TImage::RegionType AllImage,
84  unsigned &start,
85  unsigned &end)
86 {
87  // compute intersection between ray and box
88  typename TImage::IndexType ImStart = AllImage.GetIndex();
89  typename TImage::SizeType ImSize = AllImage.GetSize();
90  float Tfar = NumericTraits<float>::max();
91  float Tnear = NumericTraits<float>::NonpositiveMin();
92  float domdir = NumericTraits<float>::NonpositiveMin();
93  int sPos, ePos;
94  unsigned perpdir = 0;
95  for (unsigned i = 0; i< TImage::RegionType::ImageDimension; i++)
96  {
97  if (vcl_fabs(line[i]) > domdir)
98  {
99  domdir = vcl_fabs(line[i]);
100  perpdir = i;
101  }
102  if (vcl_fabs(line[i]) > tol)
103  {
104  int P1 = ImStart[i] - StartIndex[i];
105  int P2 = ImStart[i] + ImSize[i] - 1 - StartIndex[i];
106  float T1 = ((float)(P1))/line[i];
107  float T2 = ((float)(P2))/line[i];
108 
109  if (T1 > T2)
110  {
111  // T1 is meant to be the near face
112  std::swap(T1, T2);
113  }
114  // want the farthest Tnear and nearest TFar
115  if (T1 > Tnear)
116  {
117  Tnear = T1;
118  }
119  if (T2 < Tfar)
120  {
121  Tfar = T2;
122  }
123  }
124  else
125  {
126  // parallel to an axis - check for intersection at all
127  if ((StartIndex[i] < ImStart[i]) || (StartIndex[i] > ImStart[i] + (int)ImSize[i] - 1))
128  {
129  // no intersection
130  start=end=0;
131  return(0);
132  }
133  }
134  }
135  sPos = (int)(Tnear*vcl_fabs(line[perpdir]) + 0.5);
136  ePos = (int)(Tfar*vcl_fabs(line[perpdir]) + 0.5);
137 
138  //std::cout << Tnear << " " << Tfar << std::endl;
139  if (Tfar < Tnear) // seems to need some margin
140  {
141  // in theory, no intersection, but search between them
142  bool intersection = false;
143  unsigned inside;
144  if (Tnear - Tfar < 10)
145  {
146 // std::cout << "Searching " << Tnear << " " << Tfar << std::endl;
147  assert(ePos >= 0);
148  assert(sPos < (int)LineOffsets.size());
149  for (int i = ePos; i<= sPos; i++)
150  {
151  if (AllImage.IsInside(StartIndex + LineOffsets[i]))
152  {
153  inside = i;
154  intersection=true;
155  break;
156  }
157  }
158  }
159  if (intersection)
160  {
161 // std::cout << "Found intersection after all :: " << inside << std::endl;
162  sPos = ePos = inside;
163  assert(ePos + 1 >= 0);
164  assert(ePos + 1 < (int)LineOffsets.size());
165  while (AllImage.IsInside(StartIndex + LineOffsets[ePos + 1]))
166  {
167  ++ePos;
168  assert(ePos + 1 >= 0);
169  assert(ePos + 1 < (int)LineOffsets.size());
170  }
171  assert(sPos - 1 >= 0);
172  assert(sPos - 1 < (int)LineOffsets.size());
173  while (AllImage.IsInside(StartIndex + LineOffsets[sPos - 1]))
174  {
175  --sPos;
176  assert(sPos - 1 >= 0);
177  assert(sPos - 1 < (int)LineOffsets.size());
178  }
179  start = sPos;
180  end = ePos;
181  }
182  else
183  {
184 // std::cout << StartIndex << "No intersection" << std::endl;
185  start=end=0;
186  return(0);
187  }
188  }
189  else
190  {
191 
192  assert(sPos >= 0);
193  assert(sPos < (int)LineOffsets.size());
194  if (AllImage.IsInside(StartIndex + LineOffsets[sPos]))
195  {
196  for (;sPos>0;)
197  {
198  assert(sPos - 1 >= 0);
199  assert(sPos - 1 < (int)LineOffsets.size());
200  if (!AllImage.IsInside(StartIndex + LineOffsets[sPos - 1])) break;
201  else --sPos;
202  }
203  }
204  else
205  {
206  for(;sPos<(int)LineOffsets.size();)
207  {
208  assert(sPos >= 0);
209  assert(sPos < (int)LineOffsets.size());
210  ++sPos;
211  if (!AllImage.IsInside(StartIndex + LineOffsets[sPos])) ++sPos;
212  else break;
213  }
214  }
215  if (AllImage.IsInside(StartIndex + LineOffsets[ePos]))
216  {
217  for(;ePos<(int)LineOffsets.size();)
218  {
219  assert(ePos + 1 >= 0);
220  assert(ePos + 1 < (int)LineOffsets.size());
221  if (!AllImage.IsInside(StartIndex + LineOffsets[ePos + 1])) break;
222  else ++ePos;
223  }
224  }
225  else
226  {
227  for (;ePos>0;)
228  {
229  --ePos;
230  assert(ePos >= 0);
231  assert(ePos < (int)LineOffsets.size());
232  if (!AllImage.IsInside(StartIndex + LineOffsets[ePos])) --ePos;
233  else break;
234  }
235  }
236  }
237  start = sPos;
238  end = ePos;
239  return (1);
240 }
241 
242 
243 template <class TImage, class TBres>
244 void CopyLineToImage(const typename TImage::Pointer output,
245  const typename TImage::IndexType StartIndex,
246  const typename TBres::OffsetArray LineOffsets,
247  const typename TImage::PixelType * outbuffer,
248  const unsigned start,
249  const unsigned end)
250 {
251  unsigned size = end - start + 1;
252  for (unsigned i = 0; i <size; i++)
253  {
254  assert(start + i >= 0);
255  assert(start + i < LineOffsets.size());
256 #if 1
257  output->SetPixel(StartIndex + LineOffsets[start + i], outbuffer[i+1]); //compat
258 #else
259  typename TImage::IndexType I = StartIndex + LineOffsets[start + i];
260  output->SetPixel(I, 1 + output->GetPixel(I));
261 #endif
262  }
263 }
264 
265 
266 template <class TInputImage, class TLine>
267 typename TInputImage::RegionType
268 MakeEnlargedFace(const typename TInputImage::ConstPointer itkNotUsed( input ),
269  const typename TInputImage::RegionType AllImage,
270  const TLine line)
271 {
272 #if 0
273  // use the face calculator to produce a face list
275 FaceCalculatorType;
276  FaceCalculatorType faceCalculator;
277  typename TInputImage::SizeType radius;
278  radius.Fill(1);
279  typename FaceCalculatorType::FaceListType faceList;
280  faceList = faceCalculator(input, AllImage, radius);
281  typename FaceCalculatorType::FaceListType::iterator fit;
282  fit = faceList.begin();
283  ++fit;
284 #else
285  // the face list calculator strategy fails in multithreaded mode
286  // with 1D kernels
287  // because it doesn't return faces of the sub-blocks if they don't
288  // fall along the edge of the image
289  typedef typename TInputImage::RegionType RegionType;
290  typedef typename TInputImage::SizeType SizeType;
291  typedef typename TInputImage::IndexType IndexType;
292  typedef std::list<RegionType> FaceListType;
293  FaceListType faceList;
294 
295  for (unsigned i = 0; i < TInputImage::ImageDimension; i++)
296  {
297  RegionType R1, R2;
298  SizeType S1 = AllImage.GetSize();
299  IndexType I2 = AllImage.GetIndex();
300 
301  S1[i]=1;
302  R1 = AllImage;
303  R2 = AllImage;
304 
305  // the first face will have the same starting index and one
306  // dimension removed
307  R1.SetSize(S1);
308 
309  I2[i] = I2[i] + AllImage.GetSize()[i] - 1;
310  R2.SetSize(S1);
311  R2.SetIndex(I2);
312  faceList.push_back(R1);
313  faceList.push_back(R2);
314 // std::cout << R1 << R2 << std::endl;
315  }
316  typename FaceListType::iterator fit;
317  fit = faceList.begin();
318 #endif
319  typename TInputImage::RegionType RelevantRegion;
320  bool foundFace = false;
321  float MaxComp = NumericTraits<float>::NonpositiveMin();
322  unsigned DomDir = 0;
323  //std::cout << "------------" << std::endl;
324  // figure out the dominant direction of the line
325  for (unsigned i = 0;i< TInputImage::RegionType::ImageDimension;i++)
326  {
327  if (vcl_fabs(line[i]) > MaxComp)
328  {
329  MaxComp = vcl_fabs(line[i]);
330  DomDir = i;
331  }
332  }
333 
334  for (;fit != faceList.end();++fit)
335  {
336  // check whether this face is suitable for parallel sweeping - i.e
337  // whether the line is within 45 degrees of the perpendicular
338  // Figure out the perpendicular using the region size
339  unsigned FaceDir = 0;
340  // std::cout << "Face " << *fit << std::endl;
341  for (unsigned i = 0;i< TInputImage::RegionType::ImageDimension;i++)
342  {
343  if (fit->GetSize()[i] == 1) FaceDir = i;
344  }
345  if (FaceDir == DomDir) // within 1 degree
346  {
347  // now check whether the line goes inside the image from this face
348  if ( NeedToDoFace<ITK_TYPENAME TInputImage::RegionType, TLine>(AllImage, *fit, line) )
349  {
350 // std::cout << "Using face: " << *fit << line << std::endl;
351  RelevantRegion = *fit;
352  foundFace = true;
353  break;
354  }
355  }
356  }
357  if (foundFace)
358  {
359  // enlarge the region so that sweeping the line across it will
360  // cause all pixels to be visited.
361  // find the dimension not within the face
362  unsigned NonFaceDim = 0;
363 
364  for (unsigned i = 0; i < TInputImage::RegionType::ImageDimension;i++)
365  {
366  if (RelevantRegion.GetSize()[i] == 1)
367  {
368  NonFaceDim=i;
369  break;
370  }
371  }
372 
373  // figure out how much extra each other dimension needs to be extended
374  typename TInputImage::SizeType NewSize = RelevantRegion.GetSize();
375  typename TInputImage::IndexType NewStart = RelevantRegion.GetIndex();
376  unsigned NonFaceLen = AllImage.GetSize()[NonFaceDim];
377  for (unsigned i = 0; i < TInputImage::RegionType::ImageDimension;i++)
378  {
379  if (i != NonFaceDim)
380  {
381  int Pad = Math::Ceil<int>((float)(NonFaceLen) * line[i]/vcl_fabs(line[NonFaceDim]));
382  if (Pad < 0)
383  {
384  // just increase the size - no need to change the start
385  NewSize[i] += abs(Pad) + 1;
386  }
387  else
388  {
389  // change the size and index
390  NewSize[i] += Pad + 1;
391  NewStart[i] -= Pad + 1;
392  }
393  }
394  }
395  RelevantRegion.SetSize(NewSize);
396  RelevantRegion.SetIndex(NewStart);
397  }
398  else
399  {
400  std::cout << "Line " << line << " doesnt correspond to a face" << std::endl;
401  }
402 // std::cout << "Result region = " << RelevantRegion << std::endl;
403 
404 // std::cout << "+++++++++++++++++" << std::endl;
405  return RelevantRegion;
406 }
407 
408 template <class TImage, class TBres, class TLine>
409 int FillLineBuffer(typename TImage::ConstPointer input,
410  const typename TImage::IndexType StartIndex,
411  const TLine line, // unit vector
412  const float tol,
413  const typename TBres::OffsetArray LineOffsets,
414  const typename TImage::RegionType AllImage,
415  typename TImage::PixelType * inbuffer,
416  unsigned int &start,
417  unsigned int &end)
418 {
419 
420 // if (AllImage.IsInside(StartIndex))
421 // {
422 // start = 0;
423 // }
424 // else
425 
426 #if 0
427  // we need to figure out where to start
428  // this is an inefficient way we'll use for testing
429  for (start=0;start < LineOffsets.size();++start)
430  {
431  if (AllImage.IsInside(StartIndex + LineOffsets[start])) break;
432  }
433 #else
434  int status = ComputeStartEnd<TImage, TBres, TLine>(StartIndex, line, tol, LineOffsets, AllImage,
435  start, end);
436  if (!status) return(status);
437 #endif
438 #if 1
439  unsigned size = end - start + 1;
440  // compat
441  for (unsigned i = 0; i < size;i++)
442  {
443  assert(start + i >= 0);
444  assert(start + i < LineOffsets.size());
445  inbuffer[i+1] = input->GetPixel(StartIndex + LineOffsets[start + i]);
446  }
447 #else
449  ItType it(input, AllImage);
450  it.SetIndex(StartIndex);
451  for (unsigned i = 0; i < lastPos;i++)
452  {
453  inbuffer[i]= it.Get();
454  assert(i >= 0);
455  assert(i < LineOffsets.size());
456  typename TImage::IndexType I = StartIndex + LineOffsets[i];
457  typename TImage::OffsetType Off = I - it.GetIndex();
458  it += Off;
459  }
460 #endif
461  return(1);
462 }
463 
464 template <class TLine>
465 unsigned int GetLinePixels(const TLine line)
466 {
467  float N = line.GetNorm();
468  float correction = 0.0;
469 
470  for (unsigned int i = 0; i < TLine::Dimension; i++)
471  {
472  float tt = vcl_fabs(line[i]/N);
473  if (tt > correction) correction=tt;
474  }
475 
476  N *= correction;
477  return (int)(N + 0.5);
478 }
479 
480 } // namespace itk
481 
482 #endif

Generated at Sun Feb 3 2013 00:06:45 for Orfeo Toolbox with doxygen 1.8.1.1