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/>.
18 * @file ShroudsRegularization.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5807), University of Savoie, France
24 * Implementation of inline methods defined in ShroudsRegularization.h
26 * This file is part of the DGtal library.
30//////////////////////////////////////////////////////////////////////////////
32//////////////////////////////////////////////////////////////////////////////
34template < typename TDigitalSurfaceContainer >
36DGtal::ShroudsRegularization< TDigitalSurfaceContainer >::
41 for ( Vertex v = 0; v < myT.size(); ++v )
44 const auto s = myPtrIdxSurface->surfel( v );
45 const auto k = myPtrK->sOrthDir( s );
46 for ( Dimension i = 0; i < 3; ++i )
48 if ( i == k ) continue; // not a valid slice
49 const Scalar dn = myNextD[ i ][ v ];
50 const Scalar dp = myPrevD[ i ][ v ];
51 const Scalar l = 0.5 * ( dn + dp ); // local length
59template < typename TDigitalSurfaceContainer >
61DGtal::ShroudsRegularization< TDigitalSurfaceContainer >::
66 for ( Vertex v = 0; v < myT.size(); ++v )
68 const auto s = myPtrIdxSurface->surfel( v );
69 const auto k = myPtrK->sOrthDir( s );
70 for ( Dimension i = 0; i < 3; ++i )
72 if ( i == k ) continue; // not a valid slice
73 const Scalar dn = myNextD[ i ][ v ];
74 const Scalar dp = myPrevD[ i ][ v ];
75 const Scalar l = 0.5 * ( dn + dp ); // local length
76 const Scalar cn = 2.0 / ( dn*dn+dn*dp );
77 const Scalar cp = 2.0 / ( dp*dn+dp*dp );
78 const Scalar ci = 2.0 / ( dp*dn );
79 const RealPoint vn = position( myNext[ i ][ v ] );
80 const RealPoint vp = position( myPrev[ i ][ v ] );
81 const RealPoint vi = position( v );
82 const Scalar xp = ( vn[ i ] - vp[ i ] ) / ( dn + dp );
83 const Scalar yp = ( vn[ k ] - vp[ k ] ) / ( dn + dp );
84 const Scalar xpp = cn * vn[ i ] - ci * vi[ i ] + cp * vp[ i ];
85 const Scalar ypp = cn * vn[ k ] - ci * vi[ k ] + cp * vp[ k ];
86 E += l * ( myAlpha * ( xp * xp + yp * yp )
87 + myBeta * ( xpp * xpp + ypp * ypp ) );
93template < typename TDigitalSurfaceContainer >
95DGtal::ShroudsRegularization< TDigitalSurfaceContainer >::
96energySquaredCurvature()
100 for ( Vertex v = 0; v < myT.size(); ++v )
103 const auto s = myPtrIdxSurface->surfel( v );
104 const auto k = myPtrK->sOrthDir( s );
105 for ( Dimension i = 0; i < 3; ++i )
107 if ( i == k ) continue; // not a valid slice
108 const Scalar dn = myNextD[ i ][ v ];
109 const Scalar dp = myPrevD[ i ][ v ];
110 const Scalar l = 0.5 * ( dn + dp ); // local length
111 const Scalar cn = 2.0 / ( dn*dn+dn*dp );
112 const Scalar cp = 2.0 / ( dp*dn+dp*dp );
113 const Scalar ci = 2.0 / ( dp*dn );
114 const RealPoint vn = position( myNext[ i ][ v ] );
115 const RealPoint vp = position( myPrev[ i ][ v ] );
116 const RealPoint vi = position( v );
117 const Scalar xp = ( vn[ i ] - vp[ i ] ) / ( dn + dp );
118 const Scalar yp = ( vn[ k ] - vp[ k ] ) / ( dn + dp );
119 const Scalar xpp = cn * vn[ i ] - ci * vi[ i ] + cp * vp[ i ];
120 const Scalar ypp = cn * vn[ k ] - ci * vi[ k ] + cp * vp[ k ];
121 E += l * ( pow( xp * ypp - yp * xpp, 2.0 )
122 / pow( xp * xp + yp * yp, 3.0 ) );
128template < typename TDigitalSurfaceContainer >
129std::pair<double,double>
130DGtal::ShroudsRegularization< TDigitalSurfaceContainer >::
131oneStepAreaMinimization( const double randomization )
135 for ( Vertex v = 0; v < myT.size(); ++v )
140 const auto s = myPtrIdxSurface->surfel( v );
141 const auto k = myPtrK->sOrthDir( s );
142 for ( Dimension i = 0; i < 3; ++i )
144 if ( i == k ) continue; // not a valid slice
145 const Scalar dn = myNextD[ i ][ v ];
146 const Scalar dp = myPrevD[ i ][ v ];
147 const Scalar cn = 2.0 / ( dn*dn+dn*dp );
148 const Scalar cp = 2.0 / ( dp*dn+dp*dp );
149 const Scalar ci = 2.0 / ( dp*dn );
150 const RealPoint vn = position( myNext[ i ][ v ] );
151 const RealPoint vp = position( myPrev[ i ][ v ] );
152 const RealPoint vi = position( v );
153 const Scalar yp = ( vn[ k ] - vp[ k ] ) / ( dn + dp );
154 const Scalar xp = ( vn[ i ] - vp[ i ] ) / ( dn + dp );
155 const Scalar xpp = cn * vn[ i ] - ci * vi[ i ] + cp * vp[ i ];
156 right += yp * xpp / xp;
157 left += cn * vn[ k ] + cp * vp[ k ] - ci * myInsV[ v ][ k ];
158 coef += ci * ( myInsV[ v ][ k ] - myOutV[ v ][ k ] );
160 newT[ v ] = ( right - left ) / coef
161 + ( (double) rand() / (double) RAND_MAX - 0.49 ) * randomization;
163 // Weak damping since problem is convex.
164 auto X = positions();
165 for ( Vertex v = 0; v < myT.size(); ++v )
166 myT[ v ] = 0.9 * newT[ v ] + 0.1 * myT[ v ];
168 auto Xnext = positions();
171 for ( Vertex v = 0; v < myT.size(); ++v ) {
172 loo = std::max( loo, ( Xnext[ v ] - X[ v ] ).norm() );
173 l2 += ( Xnext[ v ] - X[ v ] ).squaredNorm();
175 return std::make_pair( loo, sqrt( l2 / myT.size() ) );
178template < typename TDigitalSurfaceContainer >
179std::pair<double,double>
180DGtal::ShroudsRegularization< TDigitalSurfaceContainer >::
181oneStepSnakeMinimization
182( const double alpha, const double beta, const double randomization )
186 for ( Vertex v = 0; v < myT.size(); ++v )
191 const auto s = myPtrIdxSurface->surfel( v );
192 const auto k = myPtrK->sOrthDir( s );
193 for ( Dimension i = 0; i < 3; ++i )
195 if ( i == k ) continue; // not a valid slice
196 const auto v_i = std::make_pair( v, i );
197 const auto vn_i = next( v_i );
198 const auto vnn_i = next( vn_i );
199 const auto vp_i = prev( v_i );
200 const auto vpp_i = prev( vp_i );
201 const auto c = c2_all( v_i );
202 const auto cn = c2_all( vn_i );
203 const auto cp = c2_all( vp_i );
204 const RealPoint Xnn = position( vnn_i.first );
205 const RealPoint Xn = position( vn_i.first );
206 const RealPoint X = position( v );
207 const RealPoint Xpp = position( vpp_i.first );
208 const RealPoint Xp = position( vp_i.first );
209 right += beta * ( - get<0>( c ) * get<0>( cn ) * Xnn[ k ]
210 + ( get<0>( c ) * get<1>( cn )
211 + get<1>( c ) * get<0>( c ) ) * Xn[ k ]
212 + ( get<2>( c ) * get<1>( cp )
213 + get<1>( c ) * get<2>( c ) ) * Xp[ k ]
214 - get<2>( c ) * get<2>( cp ) * Xpp[ k ] )
215 + alpha * ( get<0>( c ) * Xn[ k ] + get<2>( c ) * Xp[ k ] );
216 Scalar a = get<0>( c ) * get<2>( cn ) + get<1>( c ) * get<1>( c )
217 + get<2>( c ) * get<0>( cp );
218 left += ( beta * a + alpha * get<1>( c ) ) * myInsV[ v ][ k ];
219 coef += ( beta * a + alpha * get<1>( c ) )
220 * ( myOutV[ v ][ k ] - myInsV[ v ][ k ] );
222 // Possibly randomization to avoid local minima.
223 newT[ v ] = ( right - left ) / coef
224 + ( (double) rand() / (double) RAND_MAX - 0.49 ) * randomization;
226 auto X = positions();
227 // Damping between old and new positions.
228 for ( Vertex v = 0; v < myT.size(); ++v )
229 myT[ v ] = 0.5 * newT[ v ] + 0.5 * myT[ v ];
231 auto Xnext = positions();
234 for ( Vertex v = 0; v < myT.size(); ++v ) {
235 loo = std::max( loo, ( Xnext[ v ] - X[ v ] ).norm() );
236 l2 += ( Xnext[ v ] - X[ v ] ).squaredNorm();
238 return std::make_pair( loo, sqrt( l2 / myT.size() ) );
241template < typename TDigitalSurfaceContainer >
242std::pair<double,double>
243DGtal::ShroudsRegularization< TDigitalSurfaceContainer >::
244oneStepSquaredCurvatureMinimization
245( const double randomization )
249 for ( Vertex v = 0; v < myT.size(); ++v )
254 const auto s = myPtrIdxSurface->surfel( v );
255 const auto k = myPtrK->sOrthDir( s );
256 for ( Dimension i = 0; i < 3; ++i )
258 if ( i == k ) continue; // not a valid slice
259 const auto v_i = std::make_pair( v, i );
260 const auto vn_i = next( v_i );
261 const auto vnn_i = next( vn_i );
262 const auto vp_i = prev( v_i );
263 const auto vpp_i = prev( vp_i );
264 const auto c_1 = c1( v_i );
265 const auto c = c2_all( v_i );
266 const auto cn = c2_all( vn_i );
267 const auto cp = c2_all( vp_i );
268 const RealPoint xnn = position( vnn_i.first );
269 const RealPoint xn = position( vn_i.first );
270 const RealPoint x = position( v );
271 const RealPoint xpp = position( vpp_i.first );
272 const RealPoint xp = position( vp_i.first );
273 const Scalar x_1 = c_1 * ( xn[ i ] - xp[ i ] );
274 const Scalar y_1 = c_1 * ( xn[ k ] - xp[ k ] );
275 const Scalar x_2 = get<0>( c ) * xn[ i ]
276 - get<1>( c ) * x[ i ] + get<2>( c ) * xp[ i ];
277 const Scalar xn_2 = get<0>( cn ) * xnn[ i ]
278 - get<1>( cn ) * xn[ i ] + get<2>( cn ) * x[ i ];
279 const Scalar xp_2 = get<0>( cp ) * x[ i ]
280 - get<1>( cp ) * xp[ i ] + get<2>( cp ) * xpp[ i ];
281 const Scalar x_3 = c_1 * ( xn_2 - xp_2 );
282 const Scalar x_4 = get<0>( c ) * xn_2
283 - get<1>( c ) * x_2 + get<2>( c ) * xp_2;
284 const Scalar y_2 = get<0>( c ) * xn[ k ]
285 - get<1>( c ) * x[ k ] + get<2>( c ) * xp[ k ];
286 const Scalar yn_2 = get<0>( cn ) * xnn[ k ]
287 - get<1>( cn ) * xn[ k ] + get<2>( cn ) * x[ k ];
288 const Scalar yp_2 = get<0>( cp ) * x[ k ]
289 - get<1>( cp ) * xp[ k ] + get<2>( cp ) * xpp[ k ];
290 const Scalar y_3 = c_1 * ( yn_2 - yp_2 );
291 const Scalar y_4 = get<0>( c ) * yn_2
292 - get<1>( c ) * y_2 + get<2>( c ) * yp_2;
294 // We linearize Euler-Lagrange
295 // EL = 24*x'^3*x''^3*y'
296 // + x'''*( - 13*x'^4*x''*y' - 14*x'^2*x''*y'^3 - x''*y'^5 )
297 // + y'''*( 8*x'^5*x'' + 4*x'^3*x''*y'^2 - 4*x'*x''*y'^4 )
298 // + x''''*( x'^5*y' + 2*x'^3*y'^3 + x'*y'^5 )
299 // + y''*( 12*x'^4*y'*y''' + 12*x'^2*y'^3*y''' - 24*x'^4*x''^2 + 5*x'^5*x''' + 51*x'^2*x''^2*y'^2 - 2*x'^3*x'''*y'^2 + 3*x''^2*y'^4 - 7*x'*x'''*y'^4 )
300 // + y''^2*( -54*x'^3*x''*y' + 18*x'*x''*y'^3 )
301 // + y''^3*( 3*x'^4 - 21*x'^2*y'^2 )
302 // + y''''*( - x'^6 - 2*x'^4*y'^2 - x'^2*y'^4 )
304 const Scalar x_1_pow2 = x_1 * x_1;
305 const Scalar x_1_pow3 = x_1_pow2 * x_1;
306 const Scalar x_1_pow4 = x_1_pow2 * x_1_pow2;
307 const Scalar x_1_pow5 = x_1_pow4 * x_1;
308 const Scalar x_1_pow6 = x_1_pow3 * x_1_pow3;
309 const Scalar x_2_pow2 = x_2 * x_2;
310 const Scalar x_2_pow3 = x_2_pow2 * x_1;
311 const Scalar y_1_pow2 = y_1 * y_1;
312 const Scalar y_1_pow3 = y_1_pow2 * y_1;
313 const Scalar y_1_pow4 = y_1_pow2 * y_1_pow2;
314 const Scalar y_1_pow5 = y_1_pow4 * y_1;
315 // EL = 24*x'^3*x''^3*y'
316 right += - 24. * x_1_pow3 * x_2_pow3 * y_1;
317 // + x'''*( - 13*x'^4*x''*y' - 14*x'^2*x''*y'^3 - x''*y'^5 )
318 right += - x_3*( -13. * x_1_pow4 * x_2 * y_1 - 14. * x_1_pow2 * x_2 * y_1_pow3
320 // + y'''*( 8*x'^5*x'' + 4*x'^3*x''*y'^2 - 4*x'*x''*y'^4 )
321 right += - y_3*( 8. * x_1_pow5 * x_2 + 4. * x_1_pow3 * x_2 * y_1_pow2
322 - 4. * x_1 * x_2 * y_1_pow4 );
323 // + x''''*( x'^5*y' + 2*x'^3*y'^3 + x'*y'^5 )
324 right += - x_4 * ( x_1_pow5 * y_1 + 2. * x_1_pow3 * y_1_pow3 + x_1 * y_1_pow5 );
325 // + y''*( 12*x'^4*y'*y''' + 12*x'^2*y'^3*y''' - 24*x'^4*x''^2 + 5*x'^5*x''' + 51*x'^2*x''^2*y'^2 - 2*x'^3*x'''*y'^2 + 3*x''^2*y'^4 - 7*x'*x'''*y'^4 )
326 const Scalar y_2_fact =
327 12. * x_1_pow4 * y_1 * y_3
328 + 12. * x_1_pow2 * y_1_pow3 * y_3 - 24. * x_1_pow4 * x_2_pow2
329 + 5. * x_1_pow5 * x_3 + 51. * x_1_pow2 * x_2_pow2 * y_1_pow2
330 - 2. * x_1_pow3 * x_3 * y_1_pow2 + 3. * x_2_pow2 * y_1_pow4
331 - 7. * x_1 * x_3 * y_1_pow4;
332 // + y''^2*( -54*x'^3*x''*y' + 18*x'*x''*y'^3 )
333 const Scalar y_2_pow2_fact =
334 - 54. * x_1_pow3 * x_2 * y_1 + 18. * x_1 * x_2 * y_1_pow3;
335 // + y''^3*( 3*x'^4 - 21*x'^2*y'^2 )
336 const Scalar y_2_pow3_fact =
337 3. * x_1_pow4 - 21. * x_1_pow2 * y_1_pow2;
338 // + y''''*( - x'^6 - 2*x'^4*y'^2 - x'^2*y'^4 )
339 const Scalar y_4_fact =
340 - x_1_pow6 - 2. * x_1_pow4 * y_1_pow2 - x_1_pow2 * y_1_pow4;
341 const Scalar gbl_y_2_fact =
342 y_2_fact + y_2_pow2_fact * y_2 + y_2_pow3_fact * y_2 * y_2
343 - get<1>( c ) * y_4_fact;
344 right += - y_4_fact * ( get<0>( c ) * yn_2 + get<2>( c ) * yp_2 );
345 right += - gbl_y_2_fact * ( get<0>( c ) * xn[ k ] + get<2>( c ) * xp[ k ] );
346 left += -get<1>( c ) * gbl_y_2_fact * myInsV[ v ][ k ];
347 coef += -get<1>( c ) * gbl_y_2_fact * ( myOutV[ v ][ k ] - myInsV[ v ][ k ] );
350 // Possible randomization to avoid local minima.
351 newT[ v ] = ( right - left ) / coef
352 + ( (double) rand() / (double) RAND_MAX - 0.49 ) * randomization;
354 // Damping between old and new positions.
355 // Move vertices slightly toward optimal solution (since the
356 // problem has been linearized).
357 auto X = positions();
358 for ( Vertex v = 0; v < myT.size(); ++v )
359 myT[ v ] = 0.2 * newT[ v ] + 0.8 * myT[ v ];
361 auto Xnext = positions();
364 for ( Vertex v = 0; v < myT.size(); ++v ) {
365 loo = std::max( loo, ( Xnext[ v ] - X[ v ] ).norm() );
366 l2 += ( Xnext[ v ] - X[ v ] ).squaredNorm();
368 return std::make_pair( loo, sqrt( l2 / myT.size() ) );
371template < typename TDigitalSurfaceContainer >
373DGtal::ShroudsRegularization< TDigitalSurfaceContainer >::
376 for ( Vertex v = 0; v < myT.size(); ++v )
377 myT[ v ] = std::max( myEpsilon, std::min( 1.0 - myEpsilon, myT[ v ] ) );