TuttleOFX
1
|
00001 #ifndef _LENSDISTORTALGORITHM_HPP_ 00002 #define _LENSDISTORTALGORITHM_HPP_ 00003 00004 #include "lensDistortProcessParams.hpp" 00005 00006 #include <tuttle/plugin/numeric/rectOp.hpp> 00007 #include <tuttle/plugin/IProgress.hpp> 00008 #include <tuttle/plugin/exceptions.hpp> 00009 #include <terry/globals.hpp> 00010 #include <terry/point/operations.hpp> 00011 00012 #include <ofxsCore.h> 00013 00014 #include <boost/gil/image.hpp> 00015 #include <boost/gil/utilities.hpp> 00016 #include <boost/gil/typedefs.hpp> 00017 #include <boost/math/constants/constants.hpp> 00018 #include <boost/assert.hpp> 00019 00020 #include <cmath> 00021 00022 namespace terry { 00023 00024 using namespace boost::gil; 00025 00026 template <typename F, typename F2> 00027 inline point2<F> transform( const ::tuttle::plugin::lens::NormalLensDistortParams<F>& params, const point2<F2>& src ) 00028 { 00029 BOOST_ASSERT( params._distort ); 00030 BOOST_ASSERT( params._coef1 >= 0 ); 00031 point2<F> pc( params.pixelToLensCenterNormalized( src ) ); // centered normalized space 00032 pc *= params._postScale; 00033 00034 const F r2 = pc.x * pc.x + pc.y * pc.y; // distance to center squared 00035 const F coef = 1.0 + r2 * params._coef1; // distortion coef for current pixel 00036 pc.x *= coef; 00037 pc.y *= coef; 00038 00039 pc *= params._preScale; 00040 return params.lensCenterNormalizedToPixel( pc ); // original space 00041 } 00042 00043 template <typename F, typename F2> 00044 inline point2<F> transform( const ::tuttle::plugin::lens::NormalLensUndistortParams<F>& params, const point2<F2>& src ) 00045 { 00046 BOOST_ASSERT( !params._distort ); 00047 BOOST_ASSERT( params._coef1 >= 0 ); 00048 point2<F> pc( params.pixelToLensCenterNormalized( src ) ); 00049 00050 pc *= params._postScale; 00051 00052 F r = std::sqrt( pc.x * pc.x + pc.y * pc.y ); // distance to center 00053 00054 // necessary values to calculate 00055 if( r == 0 || params._coef1 == 0 ) 00056 { 00057 return params.lensCenterNormalizedToPixel( pc ); 00058 } 00059 00060 // calculate the determinant delta = Q^3 + R^2 00061 F cQ = -1.0 / ( 3.0 * params._coef1 ); 00062 F cR = -r / ( 2.f * params._coef1 ); 00063 F delta = -cQ * cQ * cQ + cR * cR; 00064 F coef = 0.0; 00065 F t; 00066 00067 // negative or positive determinant 00068 if( delta > 0 ) 00069 { 00070 coef = std::abs( cR ) + std::sqrt( delta ); 00071 coef = -std::pow( coef, 1.0 / 3.0 ); 00072 BOOST_ASSERT( coef != 0 ); 00073 coef += cQ / coef; 00074 } 00075 else if( delta < 0 ) 00076 { 00077 BOOST_ASSERT( cQ >= 0 ); 00078 BOOST_ASSERT( cR / ( sqrt( cQ * cQ * cQ ) ) <= 1 && cR / ( sqrt( cQ * cQ * cQ ) ) >= -1 ); 00079 t = std::acos( cR / ( sqrt( cQ * cQ * cQ ) ) ); 00080 coef = -2.0 * std::sqrt( cQ ) * std::cos( ( t - (boost::math::constants::pi<F>() / 2.0) ) / 3.0 ); 00081 } 00082 else 00083 { 00084 BOOST_ASSERT( 0 ); // Untreated case.. 00085 return params.lensCenterNormalizedToPixel( pc ); 00086 } 00087 00088 // get coordinates into distorded image from distorded center 00089 coef /= r; 00090 coef = std::abs( coef ); 00091 00092 pc *= coef; 00093 pc *= params._preScale; 00094 return params.lensCenterNormalizedToPixel( pc ); // to the original space 00095 } 00096 00097 /** 00098 * @todo support for fisheye... 00099 */ 00100 template <typename F, typename F2> 00101 inline point2<F> transform( const ::tuttle::plugin::lens::FisheyeLensDistortParams<F>& params, const point2<F2>& src ) 00102 { 00103 point2<F> pc( params.pixelToLensCenterNormalized( src ) ); 00104 pc *= params._postScale; 00105 00106 // F r2 = pc.x * pc.x + pc.y * pc.y; // distance to center 00107 // F coef = params._postScale * ( 1.0 + r2 * params._coef1 + ( r2 * r2 ) * params._coef2 ); // distortion coef for current pixel 00108 // pc.x *= coef; 00109 // pc.y *= coef; 00110 F r = std::sqrt( pc.x * pc.x + pc.y * pc.y ); // distance to center 00111 if( r == 0 ) 00112 { 00113 point2<F> tmp( src.x, src.y ); 00114 return tmp; 00115 } 00116 F coef = 0.5 * std::tan( r * params._coef1 ) / ( std::tan( 0.5 * params._coef1 ) * r ); 00117 00118 pc *= coef; 00119 pc *= params._preScale; 00120 return params.lensCenterNormalizedToPixel( pc ); // to the original space 00121 } 00122 00123 /** 00124 * @todo support for fisheye... 00125 */ 00126 template <typename F, typename F2> 00127 inline point2<F> transform( const ::tuttle::plugin::lens::FisheyeLensUndistortParams<F>& params, const point2<F2>& src ) 00128 { 00129 point2<F> pc( params.pixelToLensCenterNormalized( src ) ); 00130 pc *= params._postScale; 00131 00132 F r = std::sqrt( pc.x * pc.x + pc.y * pc.y ); // distance to center 00133 if( r == 0 || params._coef1 == 0 ) 00134 { 00135 point2<F> tmp( src.x, src.y ); 00136 return tmp; 00137 } 00138 F coef = std::atan( 2.0 * r * std::tan( 0.5 * params._coef1 ) ) / params._coef1; 00139 //if(rd<0) rd = -rd; 00140 coef /= r; 00141 00142 pc *= coef; 00143 pc *= params._preScale; 00144 return params.lensCenterNormalizedToPixel( pc ); // to the original space 00145 } 00146 00147 /** 00148 * @todo support for advanced lens... 00149 */ 00150 template <typename F, typename F2> 00151 inline point2<F> transform( const ::tuttle::plugin::lens::AdvancedLensDistortParams<F>& params, const point2<F2>& src ) 00152 { 00153 point2<F> pc( params.pixelToLensCenterNormalized( src ) ); 00154 pc *= params._postScale; 00155 00156 F r2 = pc.x * pc.x + pc.y * pc.y; // distance to center 00157 F r4 = r2 * r2; 00158 pc.x *= ( 1.0 + r2 * params._coef1 + r4 * params._coef2 ); 00159 pc.y *= ( 1.0 + ( r2 * params._coef1 + r4 * params._coef2 ) / params._squeeze ); 00160 00161 pc *= params._preScale; 00162 return params.lensCenterNormalizedToPixel( pc ); // to the original space 00163 } 00164 00165 } 00166 00167 namespace tuttle { 00168 namespace plugin { 00169 namespace lens { 00170 00171 template<class Params> 00172 typename Params::Point2 transformValues( const Params& params, const typename Params::Point2& p ) 00173 { 00174 return terry::transform( params, p ); 00175 } 00176 00177 /** 00178 * @brief get bounding box after the transformation of rec 00179 */ 00180 template<class Params> 00181 OfxRectD transformValues( const Params& params, const OfxRectD& rec ) 00182 { 00183 typedef typename Params::Point2 Point2; 00184 std::vector<Point2> points; 00185 00186 // center in rec ? 00187 if( params._lensCenterDst.x > rec.x1 && params._lensCenterDst.x < rec.x2 ) 00188 { 00189 points.push_back( terry::transform( params, Point2( params._lensCenterDst.x, rec.y1 ) ) ); 00190 points.push_back( terry::transform( params, Point2( params._lensCenterDst.x, rec.y2 ) ) ); 00191 } 00192 if( params._lensCenterDst.y > rec.y1 && params._lensCenterDst.y < rec.y2 ) 00193 { 00194 points.push_back( terry::transform( params, Point2( rec.x1, params._lensCenterDst.y ) ) ); 00195 points.push_back( terry::transform( params, Point2( rec.x2, params._lensCenterDst.y ) ) ); 00196 } 00197 00198 // A B 00199 // C D 00200 Point2 outA( rec.x1, rec.y1 ); 00201 Point2 outB( rec.x2, rec.y1 ); 00202 Point2 outC( rec.x1, rec.y2 ); 00203 Point2 outD( rec.x2, rec.y2 ); 00204 points.push_back( terry::transform( params, outA ) ); 00205 points.push_back( terry::transform( params, outB ) ); 00206 points.push_back( terry::transform( params, outC ) ); 00207 points.push_back( terry::transform( params, outD ) ); 00208 00209 return pointsBoundingBox( points ); 00210 } 00211 00212 /** 00213 * @param lensType 00214 * @param params 00215 * @param obj: objet to transform (can be OfxRectD, boost::gil::point2<>) 00216 */ 00217 template<class Obj> 00218 inline Obj transformValues( const EParamLensType lensType, const LensDistortProcessParams<double>& params, const Obj& obj ) 00219 { 00220 switch( lensType ) 00221 { 00222 case eParamLensTypeStandard: 00223 { 00224 if( params._distort ) 00225 { 00226 return transformValues<NormalLensDistortParams<double> >( params, obj ); 00227 } 00228 else 00229 { 00230 return transformValues<NormalLensUndistortParams<double> >( params, obj ); 00231 } 00232 } 00233 case eParamLensTypeFisheye: 00234 { 00235 if( params._distort ) 00236 return transformValues<FisheyeLensDistortParams<double> >( params, obj ); 00237 else 00238 return transformValues<FisheyeLensUndistortParams<double> >( params, obj ); 00239 } 00240 case eParamLensTypeAdvanced: 00241 { 00242 if( params._distort ) 00243 return transformValues<AdvancedLensDistortParams<double> >( params, obj ); 00244 else 00245 return transformValues<AdvancedLensUndistortParams<double> >( params, obj ); 00246 } 00247 } 00248 BOOST_THROW_EXCEPTION( exception::Unsupported() 00249 << exception::user( "Outside of the plugin fonctionnalities." ) ); 00250 return obj; 00251 } 00252 00253 /** 00254 * @brief Apply the transformation on all points inside the vector 00255 */ 00256 template<class Params, typename F2> 00257 inline void transformValuesApply( const Params& params, std::vector<boost::gil::point2<F2> >& vec ) 00258 { 00259 for( typename std::vector<boost::gil::point2<F2> >::iterator it = vec.begin(), itEnd = vec.end(); 00260 it != itEnd; 00261 ++it ) 00262 { 00263 *it = terry::transform( params, *it ); 00264 } 00265 } 00266 00267 template<class Params, typename F2> 00268 inline void transformValuesApply( const Params& params, std::vector<std::vector<boost::gil::point2<F2> > >& vec ) 00269 { 00270 for( typename std::vector<std::vector<boost::gil::point2<F2> > >::iterator it = vec.begin(), itEnd = vec.end(); 00271 it != itEnd; 00272 ++it ) 00273 { 00274 transformValuesApply( params, *it ); 00275 } 00276 } 00277 00278 template<class Obj> 00279 inline void transformValuesApply( const EParamLensType lensType, const LensDistortProcessParams<double>& params, Obj& obj ) 00280 { 00281 switch( lensType ) 00282 { 00283 case eParamLensTypeStandard: 00284 { 00285 if( params._distort ) 00286 { 00287 return transformValuesApply<NormalLensDistortParams<double> >( params, obj ); 00288 } 00289 else 00290 { 00291 return transformValuesApply<NormalLensUndistortParams<double> >( params, obj ); 00292 } 00293 } 00294 case eParamLensTypeFisheye: 00295 { 00296 if( params._distort ) 00297 return transformValuesApply<FisheyeLensDistortParams<double> >( params, obj ); 00298 else 00299 return transformValuesApply<FisheyeLensUndistortParams<double> >( params, obj ); 00300 } 00301 case eParamLensTypeAdvanced: 00302 { 00303 if( params._distort ) 00304 return transformValuesApply<AdvancedLensDistortParams<double> >( params, obj ); 00305 else 00306 return transformValuesApply<AdvancedLensUndistortParams<double> >( params, obj ); 00307 } 00308 } 00309 } 00310 00311 00312 } 00313 } 00314 } 00315 00316 #endif