1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkSpatialNeighborSubsampler_hxx
19 #define itkSpatialNeighborSubsampler_hxx
20 #include "itkSpatialNeighborSubsampler.h"
21 #include "itkImageRegionConstIteratorWithIndex.h"
22 
23 namespace itk {
24 namespace Statistics {
25 
26 template <typename TSample, typename TRegion>
27 SpatialNeighborSubsampler<TSample, TRegion>
SpatialNeighborSubsampler()28 ::SpatialNeighborSubsampler()
29 {
30   this->m_RadiusInitialized = false;
31   this->m_Radius.Fill(1);
32 }
33 
34 template <typename TSample, typename TRegion>
35 typename LightObject::Pointer
36 SpatialNeighborSubsampler<TSample, TRegion>
InternalClone() const37 ::InternalClone() const
38 {
39   typename LightObject::Pointer loPtr = Superclass::InternalClone();
40 
41   typename Self::Pointer rval =
42     dynamic_cast<Self *>(loPtr.GetPointer());
43   if(rval.IsNull())
44     {
45     itkExceptionMacro(<< "downcast to type "
46                       << this->GetNameOfClass()
47                       << " failed.");
48     }
49 
50   if (this->GetRadiusInitialized())
51     {
52     rval->SetRadius(this->GetRadius());
53     }
54   else
55     {
56     rval->m_RadiusInitialized = false;
57     }
58   return loPtr;
59 }
60 
61 template <typename TSample, typename TRegion>
62 void
63 SpatialNeighborSubsampler<TSample, TRegion>
SetRadius(const RadiusType & radius)64 ::SetRadius(const RadiusType& radius)
65 {
66   itkDebugMacro("Setting Radius to " << radius);
67   if ( !this->m_RadiusInitialized
68        || this->m_Radius != radius
69      )
70     {
71     this->m_Radius = radius;
72     this->m_RadiusInitialized = true;
73     this->Modified();
74     }
75 }
76 
77 template <typename TSample, typename TRegion>
78 void
79 SpatialNeighborSubsampler<TSample, TRegion>
SetRadius(unsigned int radius)80 ::SetRadius(unsigned int radius)
81 {
82   RadiusType radiusND;
83   radiusND.Fill(radius);
84   this->SetRadius(radiusND);
85 }
86 
87 template <typename TSample, typename TRegion>
88 void
89 SpatialNeighborSubsampler<TSample, TRegion>
Search(const InstanceIdentifier & query,SubsamplePointer & results)90 ::Search(const InstanceIdentifier& query,
91          SubsamplePointer& results)
92 {
93   if (!m_RadiusInitialized)
94     {
95     itkExceptionMacro(<< "Radius not set.");
96     }
97   if (!this->m_SampleRegionInitialized)
98     {
99     itkExceptionMacro(<< "Sample region not set.");
100     }
101   if (!this->GetRegionConstraintInitialized())
102     {
103     this->SetRegionConstraint(this->m_SampleRegion);
104     }
105 
106   results->Clear();
107   results->SetSample(this->m_Sample);
108 
109   RegionType searchRegion;
110   IndexType searchIndex;
111   SizeType searchSize;
112   IndexType endIndex;
113 
114   IndexType constraintIndex = this->m_RegionConstraint.GetIndex();
115   SizeType constraintSize = this->m_RegionConstraint.GetSize();
116 
117   IndexType queryIndex;
118   typename RegionType::OffsetTableType offsetTable;
119   this->m_SampleRegion.ComputeOffsetTable(offsetTable);
120   ImageHelperType::ComputeIndex(this->m_SampleRegion.GetIndex(),
121                                 query,
122                                 offsetTable,
123                                 queryIndex);
124 
125   for (unsigned int dim = 0; dim < RegionType::ImageDimension; ++dim)
126     {
127     if (queryIndex[dim] < static_cast<IndexValueType>(m_Radius[dim]))
128       {
129         searchIndex[dim] = std::max(NumericTraits<IndexValueType>::ZeroValue(), constraintIndex[dim]);
130       }
131     else
132       {
133       searchIndex[dim] = std::max(static_cast<IndexValueType>(queryIndex[dim] - m_Radius[dim]),
134                                       constraintIndex[dim]);
135       }
136 
137     if (queryIndex[dim] + m_Radius[dim] < constraintIndex[dim] + constraintSize[dim])
138       {
139       searchSize[dim] = queryIndex[dim] + m_Radius[dim] - searchIndex[dim] + 1;
140       }
141     else
142       {
143       searchSize[dim] = (constraintIndex[dim] + constraintSize[dim]) - searchIndex[dim];
144       }
145     endIndex[dim] = searchIndex[dim] + searchSize[dim];
146     }
147 
148   searchRegion.SetIndex(searchIndex);
149   searchRegion.SetSize(searchSize);
150 
151   if (!this->m_RegionConstraint.IsInside(queryIndex))
152     {
153     itkWarningMacro( "query point (" << query << ") corresponding to index ("
154                      << queryIndex << ") is not inside the given region constraint ("
155                      << this->m_RegionConstraint
156                      << ").  No matching points found.");
157     return;
158     }
159 
160   IndexType positionIndex = searchIndex;
161   bool someRemaining = true;
162   typename RegionType::OffsetValueType offset = 0;
163 
164   // The trouble with decoupling the region from the sample is that
165   // there is an implicit assumption that the instance identifiers in the sample
166   // are ordered as if someone was iterating forward through the region
167   // TODO Is this a safe assumption to make?
168 
169   if (this->m_CanSelectQuery ||
170       (positionIndex != queryIndex))
171     {
172     offset = 0;
173     ImageHelperType::ComputeOffset(this->m_SampleRegion.GetIndex(),
174                                    positionIndex,
175                                    offsetTable,
176                                    offset);
177     results->AddInstance(static_cast<InstanceIdentifier>(offset));
178     }
179 
180   while (someRemaining)
181     {
182     someRemaining = false;
183     for (unsigned int dim = 0; dim < ImageDimension; ++dim)
184       {
185       positionIndex[dim]++;
186       if ( positionIndex[dim] < endIndex[dim] )
187         {
188         offset += offsetTable[dim];
189         if (this->m_CanSelectQuery ||
190             (static_cast<InstanceIdentifier>(offset) != query))
191           {
192           results->AddInstance(static_cast<InstanceIdentifier>(offset));
193           }
194         someRemaining = true;
195         break;
196         }
197       else
198         {
199         offset -= offsetTable[dim] * (static_cast< typename RegionType::OffsetValueType >(searchSize[dim]) - 1);
200         positionIndex[dim] = searchIndex[dim];
201         }
202       }
203     }
204 } // end Search method
205 
206 template <typename TSample, typename TRegion>
207 void
208 SpatialNeighborSubsampler<TSample, TRegion>
PrintSelf(std::ostream & os,Indent indent) const209 ::PrintSelf(std::ostream& os, Indent indent) const
210 {
211   Superclass::PrintSelf(os, indent);
212 
213   if (m_RadiusInitialized)
214     {
215     os << indent << "Radius initialized as: " << m_Radius
216        << std::endl;
217     }
218   else
219     {
220     os << indent << "Radius not initialized yet." << std::endl;
221     }
222 
223   os << std::endl;
224 }
225 
226 }// end namespace Statistics
227 }// end namespace itk
228 
229 #endif
230