DGtal 1.3.0
Loading...
Searching...
No Matches
PowerMap.ih
1/**
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.
6 *
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.
11 *
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/>.
14 *
15 **/
16
17/**
18 * @file PowerMap.ih
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
21 *
22 * @date 2012/08/14
23 *
24 * Implementation of inline methods defined in PowerMap.h
25 *
26 * This file is part of the DGtal library.
27 */
28
29
30//////////////////////////////////////////////////////////////////////////////
31#include <cstdlib>
32
33#ifdef VERBOSE
34#include <boost/lexical_cast.hpp>
35#endif
36
37#include "DGtal/kernel/NumberTraits.h"
38
39//////////////////////////////////////////////////////////////////////////////
40
41///////////////////////////////////////////////////////////////////////////////
42// IMPLEMENTATION of inline methods.
43///////////////////////////////////////////////////////////////////////////////
44
45///////////////////////////////////////////////////////////////////////////////
46// ----------------------- Standard services ------------------------------
47
48template < typename W, typename Sep, typename Im>
49inline
50void
51DGtal::PowerMap<W, Sep,Im>::compute( )
52{
53 //We copy the image extent
54 myLowerBoundCopy = myDomainPtr->lowerBound();
55 myUpperBoundCopy = myDomainPtr->upperBound();
56
57 //Point outside the domain
58 for ( auto & coord : myInfinity )
59 coord = DGtal::NumberTraits< typename Point::Coordinate >::max();
60
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 );
68 else
69 myImagePtr->setValue ( pt, myInfinity );
70
71 //We process the dimensions one by one
72 for ( Dimension dim = 0; dim < W::Domain::Space::dimension ; dim++ )
73 computeOtherSteps ( dim );
74}
75
76template < typename W, typename Sep, typename Im>
77inline
78void
79DGtal::PowerMap<W, Sep,Im>::computeOtherSteps ( const Dimension dim ) const
80{
81#ifdef VERBOSE
82 std::string title = "Powermap dimension " + boost::lexical_cast<std::string>( dim ) ;
83 trace.beginBlock ( title );
84#endif
85
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 );
94
95 Domain localDomain(myLowerBoundCopy, myUpperBoundCopy);
96
97
98#ifdef WITH_OPENMP
99 //Parallel loop
100 std::vector<Point> subRangePoints;
101 //Starting point precomputation
102 for ( auto const & pt : localDomain.subRange( subdomain ) )
103 subRangePoints.push_back( pt );
104
105 //We run the 1D problems in //
106#pragma omp parallel for schedule(dynamic)
107 for (size_t i = 0; i < subRangePoints.size(); ++i)
108 computeOtherStep1D ( subRangePoints[i], dim);
109
110#else
111 //We solve the 1D problems sequentially
112 for ( auto const & pt : localDomain.subRange( subdomain ) )
113 computeOtherStep1D ( pt, dim);
114#endif
115
116#ifdef VERBOSE
117 trace.endBlock();
118#endif
119}
120
121// //////////////////////////////////////////////////////////////////////:
122// ////////////////////////// Other Phases
123template <typename W, typename Sep, typename Im>
124void
125DGtal::PowerMap<W,Sep,Im>::computeOtherStep1D ( const Point &startingPoint,
126 const Dimension dim) const
127{
128 ASSERT(dim < Space::dimension);
129
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];
135
136 // Extent along current dimension.
137 const auto extent = myUpperBoundCopy[dim] - myLowerBoundCopy[dim] + 1;
138
139 // Site storage.
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).
142
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 ) );
147
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.
151 if ( dim == 0 )
152 {
153 // For dim = 0, no sites are hidden.
154 for ( auto point = startPoint ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
155 {
156 const Point psite = myImagePtr->operator()( point );
157 if ( psite != myInfinity )
158 {
159 Sites.push_back( psite );
160 boundedSites.push_back( psite );
161 }
162 }
163
164 // If no sites are found, then there is nothing to do.
165 if ( Sites.size() == 0 )
166 return;
167
168 // In the periodic case and along the first dimension, the break index
169 // is at the first site found.
170 if ( isPeriodic(dim) )
171 {
172 startPoint[dim] = Sites[0][dim];
173 endPoint[dim] = startPoint[dim] + extent - 1;
174
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] );
178 }
179 }
180 else
181 {
182 // In the periodic case, the cycle depends on break index
183 if ( isPeriodic(dim) )
184 {
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();
187
188 for ( auto point = startPoint; point[dim] <= myUpperBoundCopy[dim]; ++point[dim] )
189 {
190 const Point psite = myImagePtr->operator()( point );
191
192 if ( psite != myInfinity )
193 {
194 const auto powerDist = myMetricPtr->powerDistance( point, psite, myWeightImagePtr->operator()( projectPoint( psite, dim-1 ) ) );
195 if ( powerDist < minPowerDist )
196 {
197 minPowerDist = powerDist;
198 startPoint[dim] = point[dim];
199 }
200 }
201 }
202
203 // If no sites are found, then there is nothing to do.
204 if ( minPowerDist == DGtal::NumberTraits< typename PowerSeparableMetric::Weight >::max() )
205 return;
206
207 endPoint[dim] = startPoint[dim] + extent - 1;
208 }
209
210 if ( myPeriodicityIndex.size() == 0 )
211 {
212 // Pruning the list of sites for both periodic and non-periodic cases.
213 for( auto point = startPoint ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
214 {
215 const Point psite = myImagePtr->operator()(point);
216
217 if ( psite != myInfinity )
218 {
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) ))
224 {
225 Sites.pop_back();
226 boundedSites.pop_back();
227 }
228
229 Sites.push_back( psite );
230 boundedSites.push_back( psite );
231 }
232 }
233 }
234 else
235 {
236 // Pruning the list of sites for both periodic and non-periodic cases.
237 for( auto point = startPoint ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
238 {
239 const Point psite = myImagePtr->operator()(point);
240
241 if ( psite != myInfinity )
242 {
243 const Point boundedPSite = projectPoint( psite, dim-1 );
244
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) ))
250 {
251 Sites.pop_back();
252 boundedSites.pop_back();
253 }
254
255 Sites.push_back( psite );
256 boundedSites.push_back( boundedPSite );
257 }
258 }
259 }
260
261
262 // Pruning the remaining list of sites in the periodic case.
263 if ( isPeriodic(dim) )
264 {
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.
268 {
269 Point psite = myImagePtr->operator()(point);
270
271 if ( psite != myInfinity )
272 {
273 const Point boundedPSite = projectPoint( psite, dim-1 );
274
275 // Site coordinates must be between startPoint and endPoint.
276 psite[dim] += extent;
277
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) ))
283 {
284 Sites.pop_back();
285 boundedSites.pop_back();
286 }
287
288 Sites.push_back( psite );
289 boundedSites.push_back( boundedPSite );
290 }
291 }
292 }
293 }
294
295 // No sites found
296 if ( Sites.size() == 0 )
297 return;
298
299 // Rewriting for both periodic and non-periodic cases.
300 std::size_t siteId = 0;
301 auto point = startPoint;
302
303 for ( ; point[dim] <= myUpperBoundCopy[dim] ; ++point[dim] )
304 {
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 ))
310 siteId++;
311
312 myImagePtr->setValue(point, Sites[siteId]);
313 }
314
315 // Continuing rewriting in the periodic case.
316 if ( isPeriodic(dim) )
317 {
318 for ( ; point[dim] <= endPoint[dim] ; ++point[dim] )
319 {
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 ))
325 siteId++;
326
327 myImagePtr->setValue(point - Point::base(dim, extent), Sites[siteId] - Point::base(dim, extent) );
328 }
329 }
330
331}
332
333
334/**
335 * Constructor.
336 */
337template <typename W,typename TSep,typename Im>
338inline
339DGtal::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)
346{
347 myPeriodicitySpec.fill( false );
348 myImagePtr = CountedPtr<OutputImage>(new OutputImage(aDomain));
349 compute();
350}
351
352template <typename W,typename TSep,typename Im>
353inline
354DGtal::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)
363{
364 // Finding periodic dimension index.
365 for ( Dimension i = 0; i < Space::dimension; ++i )
366 if ( isPeriodic(i) )
367 myPeriodicityIndex.push_back( i );
368
369 myImagePtr = CountedPtr<OutputImage>(new OutputImage(aDomain));
370 compute();
371}
372
373template <typename W,typename TSep,typename Im>
374inline
375typename DGtal::PowerMap<W,TSep,Im>::Point
376DGtal::PowerMap<W,TSep,Im>::projectPoint( Point aPoint, const Dimension aMaxDim ) const
377{
378 for ( std::size_t i = 0; i < myPeriodicityIndex.size() && myPeriodicityIndex[i] <= aMaxDim; ++i )
379 aPoint[ myPeriodicityIndex[i] ] = projectCoordinate( aPoint[ myPeriodicityIndex[i] ], myPeriodicityIndex[i] );
380
381 return aPoint;
382}
383
384template <typename W,typename TSep,typename Im>
385inline
386typename DGtal::PowerMap<W,TSep,Im>::Point
387DGtal::PowerMap<W,TSep,Im>::projectPoint( Point aPoint ) const
388{
389 for ( auto const & dim : myPeriodicityIndex )
390 aPoint[ dim ] = projectCoordinate( aPoint[ dim ], dim );
391
392 return aPoint;
393}
394
395template <typename W,typename TSep,typename Im>
396inline
397typename DGtal::PowerMap<W,TSep,Im>::Point::Coordinate
398DGtal::PowerMap<W,TSep,Im>::projectCoordinate( typename Point::Coordinate aCoordinate, const Dimension aDim ) const
399{
400 ASSERT( aCoordinate - myDomainPtr->lowerBound()[aDim] + myDomainExtent[aDim] >= 0 );
401 return ( aCoordinate - myDomainPtr->lowerBound()[aDim] + myDomainExtent[aDim] ) % myDomainExtent[aDim] + myDomainPtr->lowerBound()[aDim];
402}
403
404template <typename W,typename TSep,typename Im>
405inline
406void
407DGtal::PowerMap<W,TSep,Im>::selfDisplay ( std::ostream & out ) const
408{
409 out << "[PowerMap] power separable metric=" << *myMetricPtr ;
410}
411
412
413// // //
414// ///////////////////////////////////////////////////////////////////////////////
415
416template <typename W,typename TSep,typename Im>
417inline
418std::ostream&
419DGtal::operator<< ( std::ostream & out,
420 const PowerMap<W,TSep,Im> & object )
421{
422 object.selfDisplay( out );
423 return out;
424}
425
426// // //
427// ///////////////////////////////////////////////////////////////////////////////