~ubuntu-branches/ubuntu/precise/insighttoolkit/precise

« back to all changes in this revision

Viewing changes to Code/BasicFilters/itkConnectedComponentImageFilter.txx

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2008-12-19 20:16:49 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20081219201649-drt97guwl2ryt0cn

* New upstream version.
  - patches/nifti-versioning.patch: Remove.  Applied upstream.
  - control:
  - rules: Update version numbers, package names.

* control: Build-depend on uuid-dev (gdcm uses it).

* copyright: Update download URL.

* rules: Adhere to parallel=N in DEB_BUILD_OPTIONS by setting MAKEFLAGS.

* compat: Set to 7.
* control: Update build-dep on debhelper to version >= 7.

* CMakeCache.txt.debian: Set CMAKE_BUILD_TYPE to "RELEASE" so that we
  build with -O3 (not -O2), necessary to optimize the templated code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
  Program:   Insight Segmentation & Registration Toolkit
4
4
  Module:    $RCSfile: itkConnectedComponentImageFilter.txx,v $
5
5
  Language:  C++
6
 
  Date:      $Date: 2007-09-05 15:43:34 $
7
 
  Version:   $Revision: 1.22 $
 
6
  Date:      $Date: 2008-09-28 11:45:59 $
 
7
  Version:   $Revision: 1.28 $
8
8
 
9
9
  Copyright (c) Insight Software Consortium. All rights reserved.
10
10
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
66
66
template< class TInputImage, class TOutputImage, class TMaskImage >
67
67
void
68
68
ConnectedComponentImageFilter< TInputImage, TOutputImage, TMaskImage>
69
 
::GenerateData()
 
69
::BeforeThreadedGenerateData()
70
70
{
71
 
  // create a line iterator
72
 
  typedef itk::ImageLinearConstIteratorWithIndex<InputImageType>
73
 
    InputLineIteratorType;
74
 
 
75
71
  typename TOutputImage::Pointer output = this->GetOutput();
76
72
  typename TInputImage::ConstPointer input = this->GetInput();
77
73
  typename TMaskImage::ConstPointer mask = this->GetMaskImage();
84
80
    maskFilter->SetInput( input );
85
81
    maskFilter->SetInput2( mask );
86
82
    maskFilter->Update();
87
 
    input = maskFilter->GetOutput();
88
 
    }
89
 
 
90
 
  long LineIdx = 0;
91
 
  InputLineIteratorType inLineIt(input, output->GetRequestedRegion());
 
83
    m_Input = maskFilter->GetOutput();
 
84
    }
 
85
  else
 
86
    {
 
87
    m_Input = input;
 
88
    }
 
89
 
 
90
  long nbOfThreads = this->GetNumberOfThreads();
 
91
  if( itk::MultiThreader::GetGlobalMaximumNumberOfThreads() != 0 )
 
92
    {
 
93
    nbOfThreads = vnl_math_min( this->GetNumberOfThreads(), itk::MultiThreader::GetGlobalMaximumNumberOfThreads() );
 
94
    }
 
95
  // number of threads can be constrained by the region size, so call the SplitRequestedRegion
 
96
  // to get the real number of threads which will be used
 
97
  typename TOutputImage::RegionType splitRegion;  // dummy region - just to call the following method
 
98
  nbOfThreads = this->SplitRequestedRegion(0, nbOfThreads, splitRegion);
 
99
//  std::cout << "nbOfThreads: " << nbOfThreads << std::endl;
 
100
 
 
101
  // set up the vars used in the threads
 
102
  m_NumberOfLabels.clear();
 
103
  m_NumberOfLabels.resize( nbOfThreads, 0 );
 
104
  m_Barrier = Barrier::New();
 
105
  m_Barrier->Initialize( nbOfThreads );
 
106
  long pixelcount = output->GetRequestedRegion().GetNumberOfPixels();
 
107
  long xsize = output->GetRequestedRegion().GetSize()[0];
 
108
  long linecount = pixelcount/xsize;
 
109
  m_LineMap.resize( linecount );
 
110
  m_FirstLineIdToJoin.resize( nbOfThreads - 1 );
 
111
}
 
112
 
 
113
 
 
114
template< class TInputImage, class TOutputImage, class TMaskImage >
 
115
void
 
116
ConnectedComponentImageFilter< TInputImage, TOutputImage, TMaskImage>
 
117
::ThreadedGenerateData(const RegionType& outputRegionForThread,
 
118
         int threadId) 
 
119
{
 
120
  typename TOutputImage::Pointer output = this->GetOutput();
 
121
  typename TMaskImage::ConstPointer mask = this->GetMaskImage();
 
122
 
 
123
  long nbOfThreads = m_NumberOfLabels.size();
 
124
 
 
125
  // create a line iterator
 
126
  typedef itk::ImageLinearConstIteratorWithIndex<InputImageType>
 
127
    InputLineIteratorType;
 
128
  InputLineIteratorType inLineIt(m_Input, outputRegionForThread);
92
129
  inLineIt.SetDirection(0);
93
 
  LineMapType LineMap;
94
 
  // Allocate the output
95
 
  this->AllocateOutputs();
96
 
 
97
 
  long int lab = NumericTraits<long int>::Zero;
 
130
 
 
131
  // set the progress reporter to deal with the number of lines
 
132
  long pixelcountForThread = outputRegionForThread.GetNumberOfPixels();
 
133
  long xsizeForThread = outputRegionForThread.GetSize()[0];
 
134
  long linecountForThread = pixelcountForThread/xsizeForThread;
 
135
  ProgressReporter progress(this, threadId, linecountForThread * 2);
 
136
 
 
137
  // find the split axis
 
138
  IndexType outputRegionIdx = output->GetRequestedRegion().GetIndex();
 
139
  IndexType outputRegionForThreadIdx = outputRegionForThread.GetIndex();
 
140
  SizeType outputRegionSize = output->GetRequestedRegion().GetSize();
 
141
  SizeType outputRegionForThreadSize = outputRegionForThread.GetSize();
 
142
  int splitAxis = 0;
 
143
  for( int i=0; i<ImageDimension; i++ )
 
144
    {
 
145
    if( outputRegionSize[i] != outputRegionForThreadSize[i] )
 
146
      {
 
147
      splitAxis = i;
 
148
      }
 
149
    }
 
150
 
 
151
  // compute the number of pixels before that threads
 
152
  outputRegionSize[splitAxis] = outputRegionForThreadIdx[splitAxis] - outputRegionIdx[splitAxis];
 
153
  long firstLineIdForThread = RegionType( outputRegionIdx, outputRegionSize ).GetNumberOfPixels() / xsizeForThread;
 
154
  long lineId = firstLineIdForThread;
 
155
 
98
156
  OffsetVec LineOffsets;
99
 
 
100
 
  // set the progress reporter to deal with the number of lines
101
 
  long pixelcount = this->GetOutput()->GetRequestedRegion().GetNumberOfPixels();
102
 
  long xsize = this->GetOutput()->GetRequestedRegion().GetSize()[0];
103
 
  long linecount = pixelcount/xsize;
104
 
  ProgressReporter progress(this, 0, linecount * 2);
105
 
 
106
157
  SetupLineOffsets(LineOffsets);
107
158
 
 
159
  long nbOfLabels = 0;
108
160
  for( inLineIt.GoToBegin();
109
161
    !inLineIt.IsAtEnd();
110
 
    inLineIt.NextLine(), ++LineIdx)
 
162
    inLineIt.NextLine() )
111
163
    {
112
164
    inLineIt.GoToBeginOfLine();
113
165
    lineEncoding ThisLine;
115
167
      {
116
168
      InputPixelType PVal = inLineIt.Get();
117
169
      //std::cout << inLineIt.GetIndex() << std::endl;
118
 
      if (PVal != NumericTraits<InputPixelType>::Zero)
 
170
      if (PVal != m_BackgroundValue)
119
171
        {
120
172
        // We've hit the start of a run
121
173
        runLength thisRun;
122
174
        long length=0;
123
175
        IndexType thisIndex;
124
 
        ++lab;
125
176
        thisIndex = inLineIt.GetIndex();
126
177
        //std::cout << thisIndex << std::endl;
127
178
        ++length;
128
179
        ++inLineIt;
129
180
        while( !inLineIt.IsAtEndOfLine()
130
 
          && inLineIt.Get() != NumericTraits<InputPixelType>::Zero )
 
181
          && inLineIt.Get() != m_BackgroundValue )
131
182
          {
132
183
          ++length;
133
184
          ++inLineIt;
134
185
          }
135
186
        // create the run length object to go in the vector
136
187
        thisRun.length=length;
137
 
        thisRun.label=lab;
 
188
        thisRun.label=0; // will give a real label later
138
189
        thisRun.where = thisIndex;
139
190
        ThisLine.push_back(thisRun);
 
191
        nbOfLabels++;
140
192
        }
141
193
      else 
142
194
        {
143
195
        ++inLineIt;
144
196
        }
145
197
      }
146
 
    if (ThisLine.size() != 0)
147
 
      {
148
 
      //
149
 
      // There are some runs on this line, so insert it into the map.
150
 
      // This conditional insertion "breaks" the full progress report - because
151
 
      // of it, the report will not be 1.0 at the end of the execution if some
152
 
      // lines are empty - but with it, the computation time decrease from 
153
 
      // 0.059922 s to 0.0452819 s on the test image
154
 
      // http://voxel.jouy.inra.fr/darcs/contrib-itk/watershed/images/ESCells-markers.tif
155
 
      //
156
 
      LineMap[LineIdx] = ThisLine;
157
 
      }
 
198
    m_LineMap[lineId] = ThisLine;
 
199
    lineId++;
158
200
    progress.CompletedPixel();
159
201
    }
 
202
 
 
203
  m_NumberOfLabels[threadId] = nbOfLabels;
 
204
 
 
205
  // wait for the other threads to complete that part
 
206
  this->Wait();
 
207
 
 
208
  // compute the total number of labels
 
209
  nbOfLabels = 0;
 
210
  for( int i=0; i<nbOfThreads; i++ )
 
211
    {
 
212
    nbOfLabels += m_NumberOfLabels[i];
 
213
    }
160
214
  
161
 
  // set up the union find structure
162
 
  InitUnion(lab);
163
 
  // insert all the labels into the structure -- an extra loop but
164
 
  // saves complicating the ones that come later
165
 
  for (long pp = 1; pp <= lab; pp++)
 
215
  if( threadId == 0 )
166
216
    {
167
 
    InsertSet(pp);
 
217
    // set up the union find structure
 
218
    InitUnion(nbOfLabels);
 
219
    // insert all the labels into the structure -- an extra loop but
 
220
    // saves complicating the ones that come later
 
221
    typename LineMapType::iterator MapBegin, MapEnd, LineIt;
 
222
    MapBegin = m_LineMap.begin();
 
223
    MapEnd = m_LineMap.end(); 
 
224
    LineIt = MapBegin;
 
225
    unsigned long label = 1;
 
226
    for (LineIt = MapBegin; LineIt != MapEnd; ++LineIt)
 
227
      {
 
228
      typename lineEncoding::iterator cIt;
 
229
      for (cIt = LineIt->begin();cIt != LineIt->end();++cIt)
 
230
        {
 
231
        cIt->label = label;
 
232
        InsertSet(label);
 
233
        label++;
 
234
        }
 
235
      }
168
236
    }
 
237
 
 
238
  // wait for the other threads to complete that part
 
239
  this->Wait();
 
240
 
169
241
  // now process the map and make appropriate entries in an equivalence
170
242
  // table
171
 
  
172
 
 
173
 
  typename LineMapType::iterator MapBegin, MapEnd, LineIt;
174
 
 
175
 
  MapBegin = LineMap.begin();
176
 
  MapEnd = LineMap.end(); 
177
 
  LineIt = MapBegin;
178
 
 
179
 
  //while( LineIt != MapEnd)
180
 
  for (LineIt = MapBegin; LineIt != MapEnd; ++LineIt)
181
 
    {
182
 
    //lineEncoding L = LineIt->second;
183
 
    long ThisIdx = LineIt->first;
184
 
    //std::cout << "Line number = " << LineIt->first << std::endl;
185
 
    for (OffsetVec::const_iterator I = LineOffsets.begin();
186
 
         I != LineOffsets.end(); ++I)
187
 
      {
188
 
      long NeighIdx = ThisIdx + (*I);
189
 
      // check if the neighbor is in the map
190
 
      typename LineMapType::const_iterator NN = LineMap.find(NeighIdx);
191
 
      if (NN != MapEnd) 
192
 
        {
193
 
        // Now check whether they are really neighbors
194
 
        bool areNeighbors
195
 
          = CheckNeighbors(LineIt->second[0].where, NN->second[0].where);
196
 
        if (areNeighbors)
197
 
          {
198
 
          // Compare the two lines
199
 
          CompareLines(LineIt->second, NN->second);
200
 
          }
201
 
        }
202
 
      }
203
 
    }
204
 
  
205
 
  unsigned long int totalLabs = CreateConsecutive();
206
 
  m_ObjectCount = totalLabs;
207
 
  // check for overflow exception here
208
 
  if( totalLabs > static_cast<unsigned long int>(
209
 
           NumericTraits<OutputPixelType>::max() ) )
210
 
    {
211
 
    itkExceptionMacro(
212
 
      << "Number of objects greater than maximum of output pixel type " );
213
 
    }
 
243
  // assert( linecount == m_LineMap.size() );
 
244
  long pixelcount = output->GetRequestedRegion().GetNumberOfPixels();
 
245
  long xsize = output->GetRequestedRegion().GetSize()[0];
 
246
  long linecount = pixelcount/xsize;
 
247
 
 
248
  long lastLineIdForThread =  linecount;
 
249
  long nbOfLineIdToJoin = 0;
 
250
  if( threadId != nbOfThreads - 1 )
 
251
    {
 
252
    outputRegionForThreadSize = outputRegionForThread.GetSize();
 
253
    outputRegionForThreadSize[splitAxis] -= 1;
 
254
    lastLineIdForThread = firstLineIdForThread + RegionType( outputRegionIdx, outputRegionForThreadSize ).GetNumberOfPixels() / xsizeForThread;
 
255
    m_FirstLineIdToJoin[threadId] = lastLineIdForThread;
 
256
    // found the number of line ids to join
 
257
    nbOfLineIdToJoin = RegionType( outputRegionIdx, outputRegionForThread.GetSize() ).GetNumberOfPixels() / xsizeForThread
 
258
                         - RegionType( outputRegionIdx, outputRegionForThreadSize ).GetNumberOfPixels() / xsizeForThread;
 
259
    }
 
260
 
 
261
  for(long ThisIdx = firstLineIdForThread; ThisIdx < lastLineIdForThread; ++ThisIdx)
 
262
    {
 
263
    if( !m_LineMap[ThisIdx].empty() )
 
264
      {
 
265
      for (OffsetVec::const_iterator I = LineOffsets.begin();
 
266
           I != LineOffsets.end(); ++I)
 
267
        {
 
268
        long NeighIdx = ThisIdx + (*I);
 
269
        // check if the neighbor is in the map
 
270
        if ( NeighIdx >= 0 && NeighIdx < linecount && !m_LineMap[NeighIdx].empty() ) 
 
271
          {
 
272
          // Now check whether they are really neighbors
 
273
          bool areNeighbors
 
274
            = CheckNeighbors(m_LineMap[ThisIdx][0].where, m_LineMap[NeighIdx][0].where);
 
275
          if (areNeighbors)
 
276
            {
 
277
            // Compare the two lines
 
278
            CompareLines(m_LineMap[ThisIdx], m_LineMap[NeighIdx]);
 
279
            }
 
280
          }
 
281
        }
 
282
      }
 
283
    }
 
284
  
 
285
  // wait for the other threads to complete that part
 
286
  this->Wait();
 
287
 
 
288
  while( m_FirstLineIdToJoin.size() != 0 )
 
289
    {
 
290
    if( threadId * 2 < (int)m_FirstLineIdToJoin.size() )
 
291
      {
 
292
      for(long ThisIdx = m_FirstLineIdToJoin[threadId * 2];
 
293
          ThisIdx < m_FirstLineIdToJoin[threadId * 2] + nbOfLineIdToJoin;
 
294
          ++ThisIdx)
 
295
        {
 
296
        if( !m_LineMap[ThisIdx].empty() )
 
297
          {
 
298
          for (OffsetVec::const_iterator I = LineOffsets.begin();
 
299
              I != LineOffsets.end(); ++I)
 
300
            {
 
301
            long NeighIdx = ThisIdx + (*I);
 
302
            // check if the neighbor is in the map
 
303
            if ( NeighIdx >= 0 && NeighIdx < linecount && !m_LineMap[NeighIdx].empty() ) 
 
304
              {
 
305
              // Now check whether they are really neighbors
 
306
              bool areNeighbors
 
307
                = CheckNeighbors(m_LineMap[ThisIdx][0].where, m_LineMap[NeighIdx][0].where);
 
308
              if (areNeighbors)
 
309
                {
 
310
                // Compare the two lines
 
311
                CompareLines(m_LineMap[ThisIdx], m_LineMap[NeighIdx]);
 
312
                }
 
313
              }
 
314
            }
 
315
          }
 
316
        }
 
317
      }
 
318
 
 
319
    this->Wait();
 
320
 
 
321
    if( threadId == 0 )
 
322
      {
 
323
      // remove the region already joined
 
324
      typename std::vector< long > newFirstLineIdToJoin;
 
325
      for( unsigned int i = 1; i < m_FirstLineIdToJoin.size(); i += 2 )
 
326
        {
 
327
        newFirstLineIdToJoin.push_back( m_FirstLineIdToJoin[i] );
 
328
        }
 
329
      m_FirstLineIdToJoin = newFirstLineIdToJoin;
 
330
      }
 
331
 
 
332
    this->Wait();
 
333
 
 
334
    }
 
335
 
 
336
  if( threadId == 0 )
 
337
    {
 
338
    unsigned long int totalLabs = CreateConsecutive();
 
339
    m_ObjectCount = totalLabs;
 
340
    // check for overflow exception here
 
341
    if( totalLabs > static_cast<unsigned long int>(
 
342
            NumericTraits<OutputPixelType>::max() ) )
 
343
      {
 
344
      itkExceptionMacro(
 
345
        << "Number of objects greater than maximum of output pixel type " );
 
346
      }
 
347
    }
 
348
  this->Wait();
 
349
 
 
350
 
214
351
  // create the output
215
352
  // A more complex version that is intended to minimize the number of
216
353
  // visits to the output image which should improve cache
220
357
  // make much difference in practice.
221
358
  // Note - this is unnecessary if AllocateOutputs initalizes to zero
222
359
 
223
 
  FillOutput(LineMap, progress);
224
 
 
 
360
  ImageRegionIterator<OutputImageType> oit(output, outputRegionForThread);
 
361
  ImageRegionIterator<OutputImageType> fstart=oit, fend=oit;
 
362
  fstart.GoToBegin();
 
363
  fend.GoToEnd();
 
364
 
 
365
  lastLineIdForThread = firstLineIdForThread + RegionType( outputRegionIdx, outputRegionForThread.GetSize() ).GetNumberOfPixels() / xsizeForThread;
 
366
 
 
367
  for (long ThisIdx = firstLineIdForThread; ThisIdx<lastLineIdForThread; ThisIdx++)
 
368
    {
 
369
    // now fill the labelled sections
 
370
    typename lineEncoding::const_iterator cIt;
 
371
 
 
372
    for (cIt = m_LineMap[ThisIdx].begin();cIt != m_LineMap[ThisIdx].end();++cIt)
 
373
      {
 
374
      unsigned long Ilab = LookupSet( cIt->label);
 
375
      OutputPixelType lab = m_Consecutive[Ilab];
 
376
      oit.SetIndex(cIt->where);
 
377
      // initialize the non labelled pixels
 
378
      for (; fstart != oit; ++fstart)
 
379
        {
 
380
        fstart.Set( m_BackgroundValue );
 
381
        }
 
382
      for (long i = 0; i < cIt->length; ++i, ++oit)
 
383
        {
 
384
        oit.Set(lab);
 
385
        }
 
386
      fstart = oit;
 
387
      //++fstart;
 
388
      }
 
389
    progress.CompletedPixel();
 
390
    }
 
391
  // fill the rest of the image with background value
 
392
  for (; fstart != fend; ++fstart)
 
393
    {
 
394
    fstart.Set( m_BackgroundValue );
 
395
    }
 
396
 
 
397
}
 
398
 
 
399
template< class TInputImage, class TOutputImage, class TMaskImage >
 
400
void
 
401
ConnectedComponentImageFilter< TInputImage, TOutputImage, TMaskImage>
 
402
::AfterThreadedGenerateData()
 
403
{
 
404
  m_NumberOfLabels.clear();
 
405
  m_Barrier = NULL;
 
406
  m_LineMap.clear();
 
407
  m_Input = NULL;
225
408
}
226
409
 
227
410
 
236
419
  // offset for us. All this messing around produces an array of
237
420
  // offsets that will be used to index the map
238
421
  typename TOutputImage::Pointer output = this->GetOutput();
239
 
  typedef Image<long, TOutputImage::ImageDimension - 1>   PretendImageType;
240
 
  typedef typename PretendImageType::RegionType::SizeType PretendSizeType;
 
422
  typedef Image<long, TOutputImage::ImageDimension - 1>    PretendImageType;
 
423
  typedef typename PretendImageType::RegionType::SizeType  PretendSizeType;
241
424
  typedef typename PretendImageType::RegionType::IndexType PretendIndexType;
242
425
  typedef ConstShapedNeighborhoodIterator<PretendImageType>
243
426
    LineNeighborhoodType;
399
582
 
400
583
}
401
584
 
402
 
template< class TInputImage, class TOutputImage, class TMaskImage >
403
 
void
404
 
ConnectedComponentImageFilter< TInputImage, TOutputImage, TMaskImage>
405
 
::FillOutput(const LineMapType &LineMap,
406
 
             ProgressReporter &progress)
407
 
{
408
 
 
409
 
  typename LineMapType::const_iterator MapBegin, MapEnd, LineIt;
410
 
  typename TOutputImage::Pointer output = this->GetOutput();
411
 
  MapBegin = LineMap.begin();
412
 
  MapEnd = LineMap.end(); 
413
 
  LineIt = MapBegin;
414
 
 
415
 
  ImageRegionIterator<OutputImageType> oit(output,
416
 
                                           output->GetRequestedRegion());
417
 
 
418
 
  ImageRegionIterator<OutputImageType> fstart=oit, fend=oit;
419
 
  fstart.GoToBegin();
420
 
  fend.GoToEnd();
421
 
 
422
 
  for (LineIt = MapBegin; LineIt != MapEnd; ++LineIt)
423
 
    {
424
 
    // now fill the labelled sections
425
 
    typename lineEncoding::const_iterator cIt;
426
 
 
427
 
    //std::cout << LineIt->first << std::endl;
428
 
 
429
 
    for (cIt = LineIt->second.begin();cIt != LineIt->second.end();++cIt)
430
 
      {
431
 
      unsigned long Ilab = LookupSet( cIt->label);
432
 
      OutputPixelType lab = m_Consecutive[Ilab];
433
 
      oit.SetIndex(cIt->where);
434
 
      // initialize the non labelled pixels
435
 
      for (; fstart != oit; ++fstart)
436
 
        {
437
 
        fstart.Set(NumericTraits<OutputPixelType>::Zero );
438
 
        }
439
 
      for (long i = 0; i < cIt->length; ++i, ++oit)
440
 
        {
441
 
        oit.Set(lab);
442
 
        }
443
 
      fstart = oit;
444
 
      //++fstart;
445
 
      }
446
 
    progress.CompletedPixel();
447
 
    }
448
 
  // fill the rest of the image with zeros
449
 
  for (; fstart != fend; ++fstart)
450
 
    {
451
 
    fstart.Set(NumericTraits<OutputPixelType>::Zero );
452
 
    }
453
 
 
454
 
}
455
 
 
456
585
// union find related functions
457
586
template< class TInputImage, class TOutputImage, class TMaskImage >
458
587
void
468
597
::CreateConsecutive()
469
598
{
470
599
  m_Consecutive = UnionFindType(m_UnionFind.size());
471
 
  m_Consecutive[0] = 0;
 
600
  m_Consecutive[m_BackgroundValue] = m_BackgroundValue;
472
601
  unsigned long int CLab = 0;
 
602
  unsigned long int count = 0;
473
603
  for (unsigned long int I = 1; I < m_UnionFind.size(); I++)
474
604
    {
475
605
    unsigned long int L = m_UnionFind[I];
476
606
    if (L == I) 
477
607
      {
 
608
      if( CLab == m_BackgroundValue )
 
609
        {
 
610
        ++CLab;
 
611
        }
 
612
      m_Consecutive[L] = CLab;
478
613
      ++CLab;
479
 
      m_Consecutive[L] = CLab;
 
614
      ++count;
480
615
      }
481
616
    }
482
 
  return(CLab);
 
617
  return count;
483
618
}
484
619
 
485
620
template< class TInputImage, class TOutputImage, class TMaskImage >
523
658
 
524
659
  os << indent << "FullyConnected: "  << m_FullyConnected << std::endl;
525
660
  os << indent << "ObjectCount: "  << m_ObjectCount << std::endl;
 
661
  os << indent << "BackgroundValue: "  << static_cast<typename NumericTraits<OutputImagePixelType>::PrintType>(m_BackgroundValue) << std::endl;
526
662
}
527
663
 
528
664
} // end namespace itk