ITK
4.1.0
Insight Segmentation and Registration Toolkit
|
00001 /*========================================================================= 00002 * 00003 * Copyright Insight Software Consortium 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0.txt 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 * 00017 *=========================================================================*/ 00018 #ifndef __itkShapeUniqueLabelMapFilter_h 00019 #define __itkShapeUniqueLabelMapFilter_h 00020 00021 #include "itkInPlaceLabelMapFilter.h" 00022 #include "itkShapeLabelObjectAccessors.h" 00023 #include <queue> 00024 00025 namespace itk 00026 { 00040 template< class TImage > 00041 class ITK_EXPORT ShapeUniqueLabelMapFilter: 00042 public InPlaceLabelMapFilter< TImage > 00043 { 00044 public: 00046 typedef ShapeUniqueLabelMapFilter Self; 00047 typedef InPlaceLabelMapFilter< TImage > Superclass; 00048 typedef SmartPointer< Self > Pointer; 00049 typedef SmartPointer< const Self > ConstPointer; 00050 00052 typedef TImage ImageType; 00053 typedef typename ImageType::Pointer ImagePointer; 00054 typedef typename ImageType::ConstPointer ImageConstPointer; 00055 typedef typename ImageType::PixelType PixelType; 00056 typedef typename ImageType::IndexType IndexType; 00057 typedef typename ImageType::LabelObjectType LabelObjectType; 00058 typedef typename LabelObjectType::LineType LineType; 00059 00060 typedef typename LabelObjectType::AttributeType AttributeType; 00061 00063 itkStaticConstMacro(ImageDimension, unsigned int, 00064 TImage::ImageDimension); 00065 00067 itkNewMacro(Self); 00068 00070 itkTypeMacro(ShapeUniqueLabelMapFilter, 00071 InPlaceLabelMapFilter); 00072 00073 #ifdef ITK_USE_CONCEPT_CHECKING 00074 00075 /* itkConceptMacro(InputEqualityComparableCheck, 00076 (Concept::EqualityComparable<InputImagePixelType>)); 00077 itkConceptMacro(IntConvertibleToInputCheck, 00078 (Concept::Convertible<int, InputImagePixelType>)); 00079 itkConceptMacro(InputOStreamWritableCheck, 00080 (Concept::OStreamWritable<InputImagePixelType>));*/ 00081 00083 #endif 00084 00091 itkGetConstMacro(ReverseOrdering, bool); 00092 itkSetMacro(ReverseOrdering, bool); 00093 itkBooleanMacro(ReverseOrdering); 00095 00100 itkGetConstMacro(Attribute, AttributeType); 00101 itkSetMacro(Attribute, AttributeType); 00102 void SetAttribute(const std::string & s) 00103 { 00104 this->SetAttribute( LabelObjectType::GetAttributeFromName(s) ); 00105 } 00107 00108 protected: 00109 ShapeUniqueLabelMapFilter(); 00110 ~ShapeUniqueLabelMapFilter() {} 00111 00112 void GenerateData(); 00113 00114 template< class TAttributeAccessor > 00115 void TemplatedGenerateData(const TAttributeAccessor & accessor) 00116 { 00117 // Allocate the output 00118 this->AllocateOutputs(); 00119 00120 // the priority queue to store all the lines of all the objects sorted 00121 typedef typename std::priority_queue< LineOfLabelObject, std::vector< LineOfLabelObject >, 00122 LineOfLabelObjectComparator > PriorityQueueType; 00123 PriorityQueueType pq; 00124 00125 ProgressReporter progress(this, 0, 1); 00126 // TODO: really report the progress 00127 00128 for ( typename ImageType::Iterator it2( this->GetLabelMap() ); 00129 ! it2.IsAtEnd(); 00130 ++it2 ) 00131 { 00132 LabelObjectType *lo = it2.GetLabelObject(); 00133 00134 // may reduce the number of lines to proceed 00135 lo->Optimize(); 00136 00137 typename LabelObjectType::ConstLineIterator lit( lo ); 00138 while( ! lit.IsAtEnd() ) 00139 { 00140 pq.push( LineOfLabelObject(lit.GetLine(), lo) ); 00141 ++lit; 00142 } 00143 00144 // clear the lines to readd them later 00145 lo->Clear(); 00146 00147 // go to the next label 00148 // progress.CompletedPixel(); 00149 } 00150 00151 if ( pq.empty() ) 00152 { 00153 // nothing to do 00154 return; 00155 } 00156 00157 typedef typename std::deque< LineOfLabelObject > LinesType; 00158 LinesType lines; 00159 00160 lines.push_back( pq.top() ); 00161 LineOfLabelObject prev = lines.back(); 00162 IndexType prevIdx = prev.line.GetIndex(); 00163 pq.pop(); 00164 00165 while ( !pq.empty() ) 00166 { 00167 LineOfLabelObject l = pq.top(); 00168 IndexType idx = l.line.GetIndex(); 00169 pq.pop(); 00170 00171 bool newMainLine = false; 00172 // don't check dim 0! 00173 for ( unsigned int i = 1; i < ImageDimension; i++ ) 00174 { 00175 if ( idx[i] != prevIdx[i] ) 00176 { 00177 newMainLine = true; 00178 } 00179 } 00180 00181 if ( newMainLine ) 00182 { 00183 // just push the line 00184 lines.push_back(l); 00185 } 00186 else 00187 { 00188 OffsetValueType prevLength = prev.line.GetLength(); 00189 OffsetValueType length = l.line.GetLength(); 00190 00191 if ( prevIdx[0] + prevLength >= idx[0] ) 00192 { 00193 // the lines are overlapping. We need to choose which line to keep. 00194 // the label, the only "attribute" to be guarenteed to be unique, is 00195 // used to choose 00196 // which line to keep. This is necessary to avoid the case where a 00197 // part of a label is over 00198 // a second label, and below in another part of the image. 00199 bool keepCurrent; 00200 typename TAttributeAccessor::AttributeValueType prevAttr = accessor(prev.labelObject); 00201 typename TAttributeAccessor::AttributeValueType attr = accessor(l.labelObject); 00202 // this may be changed to a single boolean expression, but may become 00203 // quite difficult to read 00204 if ( attr == prevAttr ) 00205 { 00206 if ( l.labelObject->GetLabel() > prev.labelObject->GetLabel() ) 00207 { 00208 keepCurrent = !m_ReverseOrdering; 00209 } 00210 else 00211 { 00212 keepCurrent = m_ReverseOrdering; 00213 } 00214 } 00215 else 00216 { 00217 if ( attr > prevAttr ) 00218 { 00219 keepCurrent = !m_ReverseOrdering; 00220 } 00221 else 00222 { 00223 keepCurrent = m_ReverseOrdering; 00224 } 00225 } 00226 00227 if ( keepCurrent ) 00228 { 00229 // keep the current one. We must truncate the previous one to remove 00230 // the 00231 // overlap, and take care of the end of the previous line if it 00232 // extends 00233 // after the current one. 00234 if ( prevIdx[0] + prevLength > idx[0] + length ) 00235 { 00236 // the previous line is longer than the current one. Lets take its 00237 // tail and 00238 // add it to the priority queue 00239 IndexType newIdx = idx; 00240 newIdx[0] = idx[0] + length; 00241 OffsetValueType newLength = prevIdx[0] + prevLength - newIdx[0]; 00242 pq.push( LineOfLabelObject(LineType(newIdx, newLength), prev.labelObject) ); 00243 } 00244 // truncate the previous line to let some place for the current one 00245 prevLength = idx[0] - prevIdx[0]; 00246 if ( prevLength != 0 ) 00247 { 00248 lines.back(). line.SetLength(idx[0] - prevIdx[0]); 00249 } 00250 else 00251 { 00252 // length is 0 - no need to keep that line 00253 lines.pop_back(); 00254 } 00255 // and push the current one 00256 lines.push_back(l); 00257 } 00258 else 00259 { 00260 // keep the previous one. If the previous line fully overlap the 00261 // current one, 00262 // the current one is fully discarded. 00263 if ( prevIdx[0] + prevLength > idx[0] + length ) 00264 { 00265 // discarding the current line - just do nothing 00266 } 00267 else 00268 { 00269 IndexType newIdx = idx; 00270 newIdx[0] = prevIdx[0] + prevLength; 00271 OffsetValueType newLength = idx[0] + length - newIdx[0]; 00272 l.line.SetIndex(newIdx); 00273 l.line.SetLength(newLength); 00274 lines.push_back(l); 00275 } 00276 } 00277 } 00278 else 00279 { 00280 // no overlap - things are just fine already 00281 lines.push_back(l); 00282 } 00283 } 00284 00285 // store the current line as the previous one, and go to the next one. 00286 prev = lines.back(); 00287 prevIdx = prev.line.GetIndex(); 00288 } 00289 00290 // put the lines in their object 00291 for ( unsigned int i = 0; i < lines.size(); i++ ) 00292 { 00293 LineOfLabelObject & l = lines[i]; 00294 l.labelObject->AddLine(l.line); 00295 } 00296 00297 // remove objects without lines 00298 typename ImageType::Iterator it( this->GetLabelMap() ); 00299 while ( ! it.IsAtEnd() ) 00300 { 00301 typename LabelObjectType::LabelType label = it.GetLabel(); 00302 LabelObjectType *labelObject = it.GetLabelObject(); 00303 00304 if ( labelObject->Empty() ) 00305 { 00306 // must increment the iterator before removing the object to avoid 00307 // invalidating the iterator 00308 ++it; 00309 this->GetLabelMap()->RemoveLabel(label); 00310 } 00311 else 00312 { 00313 ++it; 00314 } 00315 } 00316 } 00317 00318 void PrintSelf(std::ostream & os, Indent indent) const; 00319 00320 AttributeType m_Attribute; 00321 private: 00322 ShapeUniqueLabelMapFilter(const Self &); //purposely not implemented 00323 void operator=(const Self &); //purposely not implemented 00324 00325 bool m_ReverseOrdering; 00326 struct LineOfLabelObject { 00327 typedef typename LabelObjectType::LineType LineType; 00328 LineOfLabelObject(const LineType _line, LabelObjectType *_lo) 00329 { 00330 this->line = _line; 00331 this->labelObject = _lo; 00332 } 00333 00334 LineType line; 00335 LabelObjectType *labelObject; 00336 }; 00337 00338 class LineOfLabelObjectComparator 00339 { 00340 public: 00341 bool operator()(const LineOfLabelObject & lla, const LineOfLabelObject & llb) 00342 { 00343 for ( int i = ImageDimension - 1; i >= 0; i-- ) 00344 { 00345 if ( lla.line.GetIndex()[i] > llb.line.GetIndex()[i] ) 00346 { 00347 return true; 00348 } 00349 else if ( lla.line.GetIndex()[i] < llb.line.GetIndex()[i] ) 00350 { 00351 return false; 00352 } 00353 } 00354 return false; 00355 } 00356 }; 00357 }; // end of class 00358 } // end namespace itk 00359 00360 #ifndef ITK_MANUAL_INSTANTIATION 00361 #include "itkShapeUniqueLabelMapFilter.hxx" 00362 #endif 00363 00364 #endif 00365