TuttleOFX  1
lensDistortAlgorithm.hpp
Go to the documentation of this file.
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