2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @author David Coeurjolly (\c david.coeurjolly@liris.cnrs.fr )
20 * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France
24 * Implementation of inline methods defined in PowerMap.h
26 * This file is part of the DGtal library.
30 //////////////////////////////////////////////////////////////////////////////
34 #include <boost/lexical_cast.hpp>
37 #include "DGtal/kernel/NumberTraits.h"
39 //////////////////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////////////////
42 // IMPLEMENTATION of inline methods.
43 ///////////////////////////////////////////////////////////////////////////////
45 ///////////////////////////////////////////////////////////////////////////////
46 // ----------------------- Standard services ------------------------------
48 template < typename W, typename Sep, typename Im>
51 DGtal::PowerMap<W, Sep,Im>::compute( )
53 //We copy the image extent
54 myLowerBoundCopy = myDomainPtr->lowerBound();
55 myUpperBoundCopy = myDomainPtr->upperBound();
57 //Point outside the domain
58 for ( auto & coord : myInfinity )
59 coord = DGtal::NumberTraits< typename Point::Coordinate >::max();
61 //Init the map: the power map at point p is:
62 // - p if p is an input weighted point (with weight > 0);
63 // - myInfinity otherwise.
64 for( auto const & pt : *myDomainPtr )
65 if ( myWeightImagePtr->domain().isInside( pt ) &&
66 ( myWeightImagePtr->operator()( pt ) > 0 ) )
67 myImagePtr->setValue ( pt, pt );
69 myImagePtr->setValue ( pt, myInfinity );
71 //We process the dimensions one by one
72 for ( Dimension dim = 0; dim < W::Domain::Space::dimension ; dim++ )
73 computeOtherSteps ( dim );
76 template < typename W, typename Sep, typename Im>
79 DGtal::PowerMap<W, Sep,Im>::computeOtherSteps ( const Dimension dim ) const
82 std::string title = "Powermap dimension " + boost::lexical_cast<std::string>( dim ) ;
83 trace.beginBlock ( title );
86 //We setup the subdomain iterator
87 //the iterator will scan dimension using the order:
88 // {n-1, n-2, ... 1} (we skip the '0' dimension).
89 std::vector<Dimension> subdomain;
90 subdomain.reserve(W::Domain::Space::dimension - 1);
91 for (unsigned int k = 0; k < W::Domain::Space::dimension ; k++)
92 if ( ((int)W::Domain::Space::dimension - 1 - k) != dim)
93 subdomain.push_back( (int)W::Domain::Space::dimension - 1 - k );
95 Domain localDomain(myLowerBoundCopy, myUpperBoundCopy);
100 std::vector<Point> subRangePoints;
101 //Starting point precomputation
102 for ( auto const & pt : localDomain.subRange( subdomain ) )
103 subRangePoints.push_back( pt );
105 //We run the 1D problems in //
106 #pragma omp parallel for schedule(dynamic)
107 for (int i = 0; i < (int)subRangePoints.size(); ++i) //MSCV needs signed
108 computeOtherStep1D ( subRangePoints[i], dim);
111 //We solve the 1D problems sequentially
112 for ( auto const & pt : localDomain.subRange( subdomain ) )
113 computeOtherStep1D ( pt, dim);
121 // //////////////////////////////////////////////////////////////////////:
122 // ////////////////////////// Other Phases
123 template <typename W, typename Sep, typename Im>
125 DGtal::PowerMap<W,Sep,Im>::computeOtherStep1D ( const Point &startingPoint,
126 const Dimension dim) const
128 ASSERT(dim < Space::dimension);
130 // Default starting and ending point for a cycle
131 Point startPoint = startingPoint;
132 Point endPoint = startingPoint;
133 startPoint[dim] = myLowerBoundCopy[dim];
134 endPoint[dim] = myUpperBoundCopy[dim];
136 // Extent along current dimension.
137 const auto extent = myUpperBoundCopy[dim] - myLowerBoundCopy[dim] + 1;
140 std::vector<Point> Sites; // Site coordinates with unbounded coordinates (can be outside the domain along periodic dimensions).
141 std::vector<Point> boundedSites; // Site coordinates with bounded coordinates (always inside the domain).
143 // Reserve sites storage.
144 // +1 along periodic dimension in order to store two times the site that is on break index.
145 Sites.reserve( extent + ( isPeriodic(dim) ? 1 : 0 ) );
146 boundedSites.reserve( extent + ( isPeriodic(dim) ? 1 : 0 ) );
148 // Pruning the list of sites and defining cycle bounds.
149 // In the periodic case, the cycle bounds depend on the so-called break index
150 // that defines the start point.
153 // For dim = 0, no sites are hidden.
154 for ( auto point = startPoint ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
156 const Point psite = myImagePtr->operator()( point );
157 if ( psite != myInfinity )
159 Sites.push_back( psite );
160 boundedSites.push_back( psite );
164 // If no sites are found, then there is nothing to do.
165 if ( Sites.size() == 0 )
168 // In the periodic case and along the first dimension, the break index
169 // is at the first site found.
170 if ( isPeriodic(dim) )
172 startPoint[dim] = Sites[0][dim];
173 endPoint[dim] = startPoint[dim] + extent - 1;
175 // The first site is also the last site (with appropriate shift).
176 Sites.push_back( Sites[0] + Point::base(dim, extent) );
177 boundedSites.push_back( Sites[0] );
182 // In the periodic case, the cycle depends on break index
183 if ( isPeriodic(dim) )
185 // Along other than the first dimension, the break index is at the lowest site found.
186 auto minPowerDist = DGtal::NumberTraits< typename PowerSeparableMetric::Weight >::max();
188 for ( auto point = startPoint; point[dim] <= myUpperBoundCopy[dim]; ++point[dim] )
190 const Point psite = myImagePtr->operator()( point );
192 if ( psite != myInfinity )
194 const auto powerDist = myMetricPtr->powerDistance( point, psite, myWeightImagePtr->operator()( projectPoint( psite, dim-1 ) ) );
195 if ( powerDist < minPowerDist )
197 minPowerDist = powerDist;
198 startPoint[dim] = point[dim];
203 // If no sites are found, then there is nothing to do.
204 if ( minPowerDist == DGtal::NumberTraits< typename PowerSeparableMetric::Weight >::max() )
207 endPoint[dim] = startPoint[dim] + extent - 1;
210 if ( myPeriodicityIndex.size() == 0 )
212 // Pruning the list of sites for both periodic and non-periodic cases.
213 for( auto point = startPoint ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
215 const Point psite = myImagePtr->operator()(point);
217 if ( psite != myInfinity )
219 while (( Sites.size() >= 2 ) &&
220 ( myMetricPtr->hiddenByPower(Sites[Sites.size()-2], myWeightImagePtr->operator()(Sites[Sites.size()-2]),
221 Sites[Sites.size()-1], myWeightImagePtr->operator()(Sites[Sites.size()-1]),
222 psite, myWeightImagePtr->operator()(psite),
223 startingPoint, endPoint, dim) ))
226 boundedSites.pop_back();
229 Sites.push_back( psite );
230 boundedSites.push_back( psite );
236 // Pruning the list of sites for both periodic and non-periodic cases.
237 for( auto point = startPoint ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
239 const Point psite = myImagePtr->operator()(point);
241 if ( psite != myInfinity )
243 const Point boundedPSite = projectPoint( psite, dim-1 );
245 while (( Sites.size() >= 2 ) &&
246 ( myMetricPtr->hiddenByPower(Sites[Sites.size()-2], myWeightImagePtr->operator()( projectPoint( Sites[Sites.size()-2], dim-1 ) ),
247 Sites[Sites.size()-1], myWeightImagePtr->operator()( projectPoint( Sites[Sites.size()-1], dim-1 ) ),
248 psite, myWeightImagePtr->operator()( boundedPSite ),
249 startingPoint, endPoint, dim) ))
252 boundedSites.pop_back();
255 Sites.push_back( psite );
256 boundedSites.push_back( boundedPSite );
262 // Pruning the remaining list of sites in the periodic case.
263 if ( isPeriodic(dim) )
265 auto point = startPoint;
266 point[dim] = myLowerBoundCopy[dim];
267 for ( ; point[dim] <= endPoint[dim] - extent + 1; ++point[dim] ) // +1 in order to add the break-index site at the cycle's end.
269 Point psite = myImagePtr->operator()(point);
271 if ( psite != myInfinity )
273 const Point boundedPSite = projectPoint( psite, dim-1 );
275 // Site coordinates must be between startPoint and endPoint.
276 psite[dim] += extent;
278 while (( Sites.size() >= 2 ) &&
279 ( myMetricPtr->hiddenByPower(Sites[Sites.size()-2], myWeightImagePtr->operator()(boundedSites[Sites.size()-2]),
280 Sites[Sites.size()-1], myWeightImagePtr->operator()(boundedSites[Sites.size()-1]),
281 psite, myWeightImagePtr->operator()(boundedPSite),
282 startingPoint, endPoint, dim) ))
285 boundedSites.pop_back();
288 Sites.push_back( psite );
289 boundedSites.push_back( boundedPSite );
296 if ( Sites.size() == 0 )
299 // Rewriting for both periodic and non-periodic cases.
300 std::size_t siteId = 0;
301 auto point = startPoint;
303 for ( ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
305 while ( ( siteId < Sites.size()-1 ) &&
306 ( myMetricPtr->closestPower(point,
307 Sites[siteId], myWeightImagePtr->operator()(boundedSites[siteId]),
308 Sites[siteId+1], myWeightImagePtr->operator()(boundedSites[siteId+1]))
309 != DGtal::ClosestFIRST ))
312 myImagePtr->setValue(point, Sites[siteId]);
315 // Continuing rewriting in the periodic case.
316 if ( isPeriodic(dim) )
318 for ( ; point[dim] <= endPoint[dim] ; ++point[dim] )
320 while ( ( siteId < Sites.size()-1 ) &&
321 ( myMetricPtr->closestPower(point,
322 Sites[siteId], myWeightImagePtr->operator()(boundedSites[siteId]),
323 Sites[siteId+1],myWeightImagePtr->operator()(boundedSites[siteId+1]))
324 != DGtal::ClosestFIRST ))
327 myImagePtr->setValue(point - Point::base(dim, extent), Sites[siteId] - Point::base(dim, extent) );
337 template <typename W,typename TSep,typename Im>
339 DGtal::PowerMap<W,TSep,Im>::PowerMap( ConstAlias<Domain> aDomain,
340 ConstAlias<WeightImage> aWeightImage,
341 ConstAlias<PowerSeparableMetric> aMetric)
342 : myDomainPtr(&aDomain)
343 , myDomainExtent( aDomain->upperBound() - aDomain->lowerBound() + Point::diagonal(1) )
344 , myMetricPtr(&aMetric)
345 , myWeightImagePtr(&aWeightImage)
347 myPeriodicitySpec.fill( false );
348 myImagePtr = CountedPtr<OutputImage>(new OutputImage(aDomain));
352 template <typename W,typename TSep,typename Im>
354 DGtal::PowerMap<W,TSep,Im>::PowerMap( ConstAlias<Domain> aDomain,
355 ConstAlias<WeightImage> aWeightImage,
356 ConstAlias<PowerSeparableMetric> aMetric,
357 PeriodicitySpec const & aPeriodicitySpec )
358 : myDomainPtr(&aDomain)
359 , myDomainExtent( aDomain->upperBound() - aDomain->lowerBound() + Point::diagonal(1) )
360 , myMetricPtr(&aMetric)
361 , myWeightImagePtr(&aWeightImage)
362 , myPeriodicitySpec(aPeriodicitySpec)
364 // Finding periodic dimension index.
365 for ( Dimension i = 0; i < Space::dimension; ++i )
367 myPeriodicityIndex.push_back( i );
369 myImagePtr = CountedPtr<OutputImage>(new OutputImage(aDomain));
373 template <typename W,typename TSep,typename Im>
375 typename DGtal::PowerMap<W,TSep,Im>::Point
376 DGtal::PowerMap<W,TSep,Im>::projectPoint( Point aPoint, const Dimension aMaxDim ) const
378 for ( std::size_t i = 0; i < myPeriodicityIndex.size() && myPeriodicityIndex[i] <= aMaxDim; ++i )
379 aPoint[ myPeriodicityIndex[i] ] = projectCoordinate( aPoint[ myPeriodicityIndex[i] ], myPeriodicityIndex[i] );
384 template <typename W,typename TSep,typename Im>
386 typename DGtal::PowerMap<W,TSep,Im>::Point
387 DGtal::PowerMap<W,TSep,Im>::projectPoint( Point aPoint ) const
389 for ( auto const & dim : myPeriodicityIndex )
390 aPoint[ dim ] = projectCoordinate( aPoint[ dim ], dim );
395 template <typename W,typename TSep,typename Im>
397 typename DGtal::PowerMap<W,TSep,Im>::Point::Coordinate
398 DGtal::PowerMap<W,TSep,Im>::projectCoordinate( typename Point::Coordinate aCoordinate, const Dimension aDim ) const
400 ASSERT( aCoordinate - myDomainPtr->lowerBound()[aDim] + myDomainExtent[aDim] >= 0 );
401 return ( aCoordinate - myDomainPtr->lowerBound()[aDim] + myDomainExtent[aDim] ) % myDomainExtent[aDim] + myDomainPtr->lowerBound()[aDim];
404 template <typename W,typename TSep,typename Im>
407 DGtal::PowerMap<W,TSep,Im>::selfDisplay ( std::ostream & out ) const
409 out << "[PowerMap] power separable metric=" << *myMetricPtr ;
414 // ///////////////////////////////////////////////////////////////////////////////
416 template <typename W,typename TSep,typename Im>
419 DGtal::operator<< ( std::ostream & out,
420 const PowerMap<W,TSep,Im> & object )
422 object.selfDisplay( out );
427 // ///////////////////////////////////////////////////////////////////////////////