TuttleOFX
1
|
00001 #include "../WarpPlugin.hpp" 00002 #include "../WarpProcess.hpp" 00003 #include "../WarpDefinitions.hpp" 00004 #include "tps.hpp" 00005 00006 #include <terry/globals.hpp> 00007 #include <tuttle/plugin/global.hpp> 00008 00009 #include <ofxsImageEffect.h> 00010 #include <ofxsMultiThread.h> 00011 00012 #include <boost/gil/gil_all.hpp> 00013 #include <boost/numeric/conversion/cast.hpp> 00014 #include <boost/numeric/ublas/io.hpp> 00015 #include <boost/numeric/ublas/lu.hpp> 00016 #include <boost/numeric/ublas/matrix.hpp> 00017 #include <boost/numeric/ublas/matrix_proxy.hpp> 00018 #include <boost/numeric/ublas/vector.hpp> 00019 #include <boost/algorithm/string/predicate.hpp> 00020 #include <boost/math/special_functions/pow.hpp> 00021 #include <boost/foreach.hpp> 00022 00023 #include <vector> 00024 #include <ostream> 00025 00026 #define TPS_NORMALIZE_COORD 00027 00028 namespace tuttle { 00029 namespace plugin { 00030 namespace warp { 00031 00032 template<class Mat> 00033 inline std::ostream& coutMat( std::ostream& os, const Mat& m ) 00034 { 00035 os << "[" << m.size1() << "," << m.size2() << "]\n"; 00036 for( std::size_t y = 0; y < m.size1(); ++y ) 00037 { 00038 os << "("; 00039 for( std::size_t x = 0; x < m.size2(); ++x ) 00040 { 00041 os << boost::format("%4.3d") % m(y,x); 00042 if( x < m.size2() - 1 ) 00043 { 00044 os << ",\t"; 00045 } 00046 } 00047 os << ")"; 00048 if( y < m.size1() - 1 ) 00049 { 00050 os << ","; 00051 } 00052 os << "\n"; 00053 } 00054 return os; 00055 } 00056 00057 /** 00058 * @brief Radial basis function: Thin plate spline (a special polyharmonic spline). 00059 * 00060 * @f[ 00061 * r^2 * log(r) 00062 * @f[ 00063 * 00064 * @param r2 squared distance value 00065 * @return Computed weight value 00066 */ 00067 inline double base_func( const double r2 ) 00068 { 00069 using boost::math::pow; 00070 if( r2 == 0 ) 00071 return 0.0; 00072 static const double v = 1.0 / ( 2.0 * log(10.0) ); 00073 return r2 * log( r2 ) * v; 00074 // return r2 * log( std::sqrt(r2) ); // same as above solution 00075 00076 // return pow<2>(r2) * log( std::sqrt(r2) ); // r^4 * log(r) 00077 // return pow<3>( std::sqrt(r2) ); // r^3 00078 // return std::sqrt(r2); // r 00079 // return r2; // r^2 00080 } 00081 00082 template<typename SCALAR> 00083 TPS_Morpher<SCALAR>::TPS_Morpher() 00084 {} 00085 00086 00087 /** 00088 * 00089 * @param pIn 00090 * @param pOut 00091 * @param regularization Amount of "relaxation", 0.0 = exact interpolation 00092 * @param applyWarp 00093 * @param nbPoints 00094 */ 00095 template<typename SCALAR> 00096 void TPS_Morpher<SCALAR>::setup( const std::vector< Point2 > pIn, const std::vector< Point2 > pOut, const double regularization, const bool applyWarp, const std::size_t width, const std::size_t height, const double transition ) 00097 { 00098 using boost::math::pow; 00099 00100 _width = width; 00101 _height = height; 00102 _transition = transition; 00103 00104 #ifdef TPS_NORMALIZE_COORD 00105 _pIn.reserve( pIn.size() ); 00106 _pOut.reserve( pOut.size() ); 00107 BOOST_FOREACH( const Point2& p, pIn ) 00108 { 00109 Point2 np( p.x / _width, p.y / _height ); 00110 _pIn.push_back( np ); 00111 } 00112 BOOST_FOREACH( const Point2& p, pOut ) 00113 { 00114 Point2 np( p.x / _width, p.y / _height ); 00115 _pOut.push_back( np ); 00116 } 00117 #else 00118 _pIn = pIn; 00119 _pOut = pOut; 00120 #endif 00121 00122 _nbPoints = _pIn.size(); 00123 _mat_L.resize( _nbPoints + 3, _nbPoints + 3 ); 00124 _mat_V.resize( _nbPoints + 3, 2 ); 00125 _mat_K.resize( _nbPoints, _nbPoints ); 00126 _activateWarp = applyWarp; 00127 00128 //TUTTLE_TCOUT_VAR( _pIn.size() ); 00129 //TUTTLE_TCOUT_VAR( _pOut.size() ); 00130 00131 BOOST_ASSERT( _pIn.size() == _pOut.size() ); 00132 00133 // Fill K and directly copy values into L 00134 // K = [ 0 U(r01) ... U(r0n) ] 00135 // = [ U(r10) 0 ... U(r1n) ] 00136 // = [ ... ... ... ... ] 00137 // = [ U(rn0) U(rn1) ... 0 ] 00138 // 00139 // K.size = n x n 00140 for( std::size_t y = 0; y < _nbPoints; ++y ) 00141 { 00142 const Point2& point_i = _pIn[y]; 00143 for( std::size_t x = 0; x < _nbPoints; ++x ) 00144 { 00145 if( y == x ) 00146 { 00147 _mat_L( y, x ) = _mat_K( y, x ) = regularization; 00148 // diagonal: reqularization parameters (lambda * a^2) 00149 // _mat_L( i, i ) = _mat_K( i, i ) = regularization /** (a*a)*/; 00150 } 00151 else 00152 { 00153 const Point2& point_j = _pIn[x]; 00154 const Scalar sum = pow<2>( point_i.x - point_j.x ) + pow<2>( point_i.y - point_j.y ); 00155 _mat_L( y, x ) = _mat_K( y, x ) = base_func( sum ); 00156 } 00157 } 00158 } 00159 00160 // fill L with P and trans(P) 00161 // 00162 // P = [ 1 x1 y1 ] 00163 // [ 1 x2 y2 ] 00164 // [ ... ... ... ] 00165 // [ 1 xn yn ] 00166 // 00167 // P.size = n x 3 00168 for( std::size_t i = 0; i < _nbPoints; ++i ) 00169 { 00170 const Point2& pt = _pIn[i]; 00171 _mat_L( i, _nbPoints + 0 ) = 1.0; 00172 _mat_L( i, _nbPoints + 1 ) = pt.x; 00173 _mat_L( i, _nbPoints + 2 ) = pt.y; 00174 00175 _mat_L( _nbPoints + 0, i ) = 1.0; 00176 _mat_L( _nbPoints + 1, i ) = pt.x; 00177 _mat_L( _nbPoints + 2, i ) = pt.y; 00178 } 00179 00180 // L = [ K | P ] 00181 // [ | 000 ] 00182 // [ trans(P) | 000 ] 00183 // [ | 000 ] 00184 // 00185 // L.size = (n+3) x (n+3) 00186 for( std::size_t i = 0; i < 3; ++i ) 00187 { 00188 for( std::size_t j = 0; j < 3; ++j ) 00189 { 00190 _mat_L( _nbPoints+i, _nbPoints+j ) = 0.0; 00191 } 00192 } 00193 00194 // Fill V 00195 // V = [ x1' x2' ... xn' 000 ] 00196 // [ y1' y2' ... yn' 000 ] 00197 // 00198 // V.size = 2 x (n+3) 00199 // here we manipulate trans(V) 00200 for( std::size_t i = 0; i < _nbPoints; ++i ) 00201 { 00202 const Point2& pIn = _pIn[i]; 00203 const Point2& pOut = _pOut[i]; 00204 _mat_V( i, 0 ) = pOut.x - pIn.x; 00205 _mat_V( i, 1 ) = pOut.y - pIn.y; 00206 //TUTTLE_TCOUT_VAR2( pOut.x, pIn.x ); 00207 //TUTTLE_TCOUT_VAR2( pOut.y, pIn.y ); 00208 } 00209 00210 _mat_V( _nbPoints + 0, 0 ) = _mat_V( _nbPoints + 1, 0 ) = _mat_V( _nbPoints + 2, 0 ) = 0.0; 00211 _mat_V( _nbPoints + 0, 1 ) = _mat_V( _nbPoints + 1, 1 ) = _mat_V( _nbPoints + 2, 1 ) = 0.0; 00212 00213 //TUTTLE_TCOUT(""); 00214 //TUTTLE_TCOUT( "mtx_v" ); 00215 //coutMat( std::cout, _mat_V ); 00216 //TUTTLE_TCOUT(""); 00217 //TUTTLE_TCOUT( "mtx_orig_k" ); 00218 //coutMat( std::cout, _mat_K ); 00219 //TUTTLE_TCOUT(""); 00220 //TUTTLE_TCOUT( "mtx_l" ); 00221 //coutMat( std::cout, _mat_L ); 00222 //TUTTLE_TCOUT(""); 00223 00224 // Solve the linear system "inplace" 00225 permutation_matrix<Scalar> P( _nbPoints + 3 ); 00226 // matrix<Scalar> x( _nbPoints + 3, 2 ); 00227 00228 lu_factorize( _mat_L, P ); 00229 lu_substitute( _mat_L, P, _mat_V ); 00230 00231 //TUTTLE_TCOUT_X( 10, "-"); 00232 //TUTTLE_TCOUT( "mtx_v" ); 00233 //coutMat( std::cout, _mat_V ); 00234 //TUTTLE_TCOUT(""); 00235 //TUTTLE_TCOUT( "mtx_l" ); 00236 //coutMat( std::cout, _mat_L ); 00237 //TUTTLE_TCOUT(""); 00238 //TUTTLE_TCOUT_X( 80, "_"); 00239 } 00240 00241 template<typename SCALAR> 00242 template<typename S2> 00243 typename TPS_Morpher<SCALAR>::Point2 TPS_Morpher<SCALAR>::operator( )( const point2<S2>& pt ) const 00244 { 00245 using boost::math::pow; 00246 if( !_activateWarp || _nbPoints <= 1 ) 00247 { 00248 return Point2( pt.x, pt.y ); 00249 } 00250 #ifdef TPS_NORMALIZE_COORD 00251 const Point2 npt( pt.x / _width, pt.y / _height ); 00252 #else 00253 const Point2 npt( pt.x, pt.y ); 00254 #endif 00255 00256 // Nombre de colonnes de la matrice K 00257 const std::size_t m = _mat_K.size2( ); 00258 00259 double dx = _mat_V( m + 0, 0 ) + _mat_V( m + 1, 0 ) * npt.x + _mat_V( m + 2, 0 ) * npt.y; 00260 double dy = _mat_V( m + 0, 1 ) + _mat_V( m + 1, 1 ) * npt.x + _mat_V( m + 2, 1 ) * npt.y; 00261 00262 Const_Matrix_Col mat_Vx( _mat_V, 0 ); 00263 Const_Matrix_Col mat_Vy( _mat_V, 1 ); 00264 00265 std::vector< point2<double> >::const_iterator it_out = _pOut.begin(); 00266 typename Const_Matrix_Col::const_iterator it_Vx( mat_Vx.begin() ); 00267 typename Const_Matrix_Col::const_iterator it_Vy( mat_Vy.begin() ); 00268 00269 //std::cout<<"DX fin "<<dx<<" "<<dy<<std::endl; 00270 00271 for( std::size_t i = 0; 00272 i < m; 00273 ++i, ++it_out, ++it_Vx, ++it_Vy ) 00274 { 00275 const double d = base_func( pow<2>( it_out->x - npt.x ) + pow<2>( it_out->y - npt.y ) ); 00276 dx += ( *it_Vx ) * d; 00277 dy += ( *it_Vy ) * d; 00278 } 00279 dx *= _transition; 00280 dy *= _transition; 00281 #ifdef TPS_NORMALIZE_COORD 00282 return Point2( (npt.x+dx)*_width, (npt.y+dy)*_height ); 00283 #else 00284 return Point2( npt.x+dx, npt.y+dy ); 00285 #endif 00286 } 00287 00288 } 00289 } 00290 } 00291 00292