TuttleOFX  1
LensDistortPlugin.cpp
Go to the documentation of this file.
00001 #include "LensDistortPlugin.hpp"
00002 #include "LensDistortProcess.hpp"
00003 #include "lensDistortAlgorithm.hpp" // to compute RoI
00004 
00005 #include <tuttle/plugin/ofxToGil/point.hpp>
00006 #include <tuttle/plugin/numeric/coordinateSystem.hpp>
00007 
00008 #include <ofxsImageEffect.h>
00009 #include <ofxsMultiThread.h>
00010 #include <ofxsParam.h>
00011 
00012 namespace tuttle {
00013 namespace plugin {
00014 namespace lens {
00015 
00016 OfxRectD LensDistortPlugin::_dstRoi     = { 0, 0, 0, 0 };
00017 OfxRectD LensDistortPlugin::_srcRoi     = { 0, 0, 0, 0 };
00018 OfxRectD LensDistortPlugin::_srcRealRoi = { 0, 0, 0, 0 };
00019 
00020 LensDistortPlugin::LensDistortPlugin( OfxImageEffectHandle handle )
00021         : SamplerPlugin( handle )
00022 {
00023         _srcRefClip = fetchClip( kClipOptionalSourceRef );
00024 
00025         _reverse              = fetchBooleanParam       ( kParamReverse );
00026         _displaySource        = fetchBooleanParam       ( kParamDisplaySource );
00027         _lensType             = fetchChoiceParam        ( kParamLensType );
00028         _coef1                = fetchDoubleParam        ( kParamCoef1 );
00029         _coef2                = fetchDoubleParam        ( kParamCoef2 );
00030         _squeeze              = fetchDoubleParam        ( kParamSqueeze );
00031         _asymmetric           = fetchDouble2DParam      ( kParamAsymmetric );
00032         _center               = fetchDouble2DParam      ( kParamCenter );
00033         _centerOverlay        = fetchBooleanParam       ( kParamCenterOverlay );
00034         _centerType           = fetchChoiceParam        ( kParamCenterType );
00035         _preScale             = fetchDoubleParam        ( kParamPreScale );
00036         _postScale            = fetchDoubleParam        ( kParamPostScale );
00037         _resizeRod            = fetchChoiceParam        ( kParamResizeRod );
00038         _resizeRodManualScale = fetchDoubleParam        ( kParamResizeRodManualScale );
00039         _groupDisplayParams   = fetchGroupParam         ( kParamDisplayOptions );
00040         _gridOverlay          = fetchBooleanParam       ( kParamGridOverlay );
00041         _gridCenter           = fetchDouble2DParam      ( kParamGridCenter );
00042         _gridCenterOverlay    = fetchBooleanParam       ( kParamGridCenterOverlay );
00043         _gridScale            = fetchDouble2DParam      ( kParamGridScale );
00044         _debugDisplayRoi      = fetchBooleanParam       ( kParamDebugDisplayRoi );
00045 
00046         initParamsProps();
00047 }
00048 
00049 void LensDistortPlugin::initParamsProps()
00050 {
00051         static const OFX::InstanceChangedArgs args;
00052 
00053         changedParam( args, kParamFilter );
00054         changedParam( args, kParamLensType );
00055         changedParam( args, kParamResizeRod );
00056 }
00057 
00058 /**
00059  * @brief The overridden render function
00060  * @param[in]   args     Rendering parameters
00061  */
00062 void LensDistortPlugin::render( const OFX::RenderArguments& args )
00063 {
00064         doGilRender<LensDistortProcess>( *this, args );
00065 }
00066 
00067 void LensDistortPlugin::changedParam( const OFX::InstanceChangedArgs& args, const std::string& paramName )
00068 {
00069         SamplerPlugin::changedParam( args, paramName );
00070 
00071         if( paramName == kParamLensType )
00072         {
00073                 switch( _lensType->getValue() )
00074                 {
00075                         case 0: // normal
00076                                 _coef2      -> setIsSecret( true );
00077                                 _coef2      -> setEnabled( false );
00078                                 _squeeze    -> setIsSecret( true );
00079                                 _squeeze    -> setEnabled( false );
00080                                 _asymmetric -> setIsSecret( true );
00081                                 _asymmetric -> setEnabled( false );
00082                                 break;
00083                         case 1: // fish-eye
00084                                 _coef2      ->setIsSecret( false );
00085                                 _coef2      -> setEnabled( true );
00086                                 _squeeze    -> setIsSecret( true );
00087                                 _squeeze    -> setEnabled( false );
00088                                 _asymmetric -> setIsSecret( true );
00089                                 _asymmetric -> setEnabled( false );
00090                                 break;
00091                         case 2: // advanced
00092                                 _coef2      -> setIsSecret( false );
00093                                 _coef2      -> setEnabled( true );
00094                                 _squeeze    -> setIsSecret( false );
00095                                 _squeeze    -> setEnabled( true );
00096                                 _asymmetric -> setIsSecret( false );
00097                                 _asymmetric -> setEnabled( true );
00098                                 break;
00099                         default:
00100                                 BOOST_THROW_EXCEPTION( exception::Bug()
00101                                         << exception::user() + "Lens type value not recognize." );
00102                                 break;
00103                 }
00104         }
00105         else if( paramName == kParamResizeRod )
00106         {
00107                 if( _resizeRod->getValue() == eParamResizeRodManual )
00108                 {
00109                         _resizeRodManualScale -> setIsSecret( false );
00110                         _resizeRodManualScale -> setEnabled( true );
00111                 }
00112                 else
00113                 {
00114                         //                      _resizeRodManualScale->setIsSecret( true );
00115                         _resizeRodManualScale -> setEnabled( false );
00116                 }
00117         }
00118         else if( paramName == kParamGridOverlay || paramName == kParamGridCenter || paramName == kParamGridScale )
00119         {
00120                 redrawOverlays();
00121         }
00122 }
00123 
00124 bool LensDistortPlugin::isIdentity( const OFX::RenderArguments& args, OFX::Clip*& identityClip, double& identityTime )
00125 {
00126         bool isIdentity = false;
00127 
00128         if( _displaySource->getValue() )
00129         {
00130                 isIdentity = true;
00131         }
00132         else if( _coef1->getValue() == 0 /*_coef1->getDefault( )*/ &&
00133                  _preScale->getValue() == _preScale->getDefault() &&
00134                  _postScale->getValue() == _postScale->getDefault() &&
00135                  ( !_coef2->getIsEnable() || _coef2->getValue() == _coef2->getDefault() ) &&
00136                  ( !_squeeze->getIsEnable() || _squeeze->getValue() == _squeeze->getDefault() ) &&
00137                  ( !_asymmetric->getIsEnable() || _asymmetric->getValue() == _asymmetric->getDefault() ) )
00138         {
00139                 isIdentity = true;
00140         }
00141         if( isIdentity )
00142         {
00143                 identityClip = _clipSrc;
00144                 identityTime = args.time;
00145                 return true;
00146         }
00147         return false;
00148 }
00149 
00150 bool LensDistortPlugin::getRegionOfDefinition( const OFX::RegionOfDefinitionArguments& args, OfxRectD& rod )
00151 {
00152         using namespace bgil;
00153         const OfxRectD srcRod = _clipSrc->getCanonicalRod( args.time );
00154         const Point2 srcRodCorner( srcRod.x1, srcRod.y1 );
00155         const Point2 srcRodSize( srcRod.x2 - srcRod.x1, srcRod.y2 - srcRod.y1 );
00156         const OfxRectD srcRodInDstFrame = { 0, 0, srcRodSize.x, srcRodSize.y };
00157 
00158         bool modified = false;
00159 
00160         LensDistortProcessParams<Scalar> params( getProcessParams( srcRod, srcRod, _clipDst->getPixelAspectRatio(), true ) );
00161         switch( static_cast<EParamResizeRod>( _resizeRod->getValue() ) )
00162         {
00163                 case eParamResizeRodNo:
00164                 {
00165                         rod = srcRod;
00166                         return false;
00167                 }
00168                 case eParamResizeRodSourceRef:
00169                 {
00170                         if( !_srcRefClip->isConnected() )
00171                                 return false;
00172                         rod = _srcRefClip->getCanonicalRod( args.time );
00173                         return true;
00174                 }
00175                 case eParamResizeRodMin:
00176                 {
00177                         Point2 tl = transformValues( getLensType(), params, Point2( srcRodInDstFrame.x1, srcRodInDstFrame.y1 ) ); // top left
00178                         Point2 tr = transformValues( getLensType(), params, Point2( srcRodInDstFrame.x2, srcRodInDstFrame.y1 ) ); // top right
00179                         Point2 bl = transformValues( getLensType(), params, Point2( srcRodInDstFrame.x1, srcRodInDstFrame.y2 ) ); // bottom left
00180                         Point2 br = transformValues( getLensType(), params, Point2( srcRodInDstFrame.x2, srcRodInDstFrame.y2 ) ); // bottom right
00181                         point2<double> pMin; // top left corner
00182                         point2<double> pMax; // down right corner
00183 
00184                         pMin.x = std::max( tl.x, bl.x );
00185                         pMin.y = std::max( tl.y, tr.y );
00186                         pMax.x = std::min( tr.x, br.x );
00187                         pMax.y = std::min( bl.y, br.y );
00188 
00189                         if( params._lensCenterSrc.x > srcRodInDstFrame.x1 && params._lensCenterSrc.x < srcRodInDstFrame.x2 )
00190                         {
00191                                 Point2 t = transformValues( getLensType(), params, Point2( params._lensCenterSrc.x, srcRodInDstFrame.y1 ) );
00192                                 pMin.y = std::max( pMin.y, t.y );
00193                                 Point2 b = transformValues( getLensType(), params, Point2( params._lensCenterSrc.x, srcRodInDstFrame.y2 ) );
00194                                 pMax.y = std::min( pMax.y, b.y );
00195                         }
00196                         if( params._lensCenterSrc.y > srcRodInDstFrame.y1 && params._lensCenterSrc.y < srcRodInDstFrame.y2 )
00197                         {
00198                                 Point2 l = transformValues( getLensType(), params, Point2( srcRodInDstFrame.x1, params._lensCenterSrc.y ) );
00199                                 pMin.x = std::max( pMin.x, l.x );
00200                                 Point2 r = transformValues( getLensType(), params, Point2( srcRodInDstFrame.x2, params._lensCenterSrc.y ) );
00201                                 pMax.x = std::min( pMax.x, r.x );
00202                         }
00203                         rod.x1   = pMin.x;
00204                         rod.y1   = pMin.y;
00205                         rod.x2   = pMax.x;
00206                         rod.y2   = pMax.y;
00207                         modified = true;
00208                         break;
00209                 }
00210                 case eParamResizeRodMax:
00211                 {
00212                         rod      = transformValues( getLensType(), params, srcRodInDstFrame );
00213                         modified = true;
00214                         break;
00215                 }
00216                 case eParamResizeRodManual:
00217                 {
00218                         double scale = _resizeRodManualScale->getValue();
00219                         if( scale == 1.0 )
00220                                 return false;
00221 
00222                         point2<double> pMin( srcRodInDstFrame.x1, srcRodInDstFrame.y1 ); // top left corner
00223                         point2<double> pMax( srcRodInDstFrame.x2, srcRodInDstFrame.y2 ); // down right corner
00224                         point2<double> center( srcRodSize * 0.5 );
00225                         pMin     = ( ( pMin - center ) * scale ) + center;
00226                         pMax     = ( ( pMax - center ) * scale ) + center;
00227                         rod.x1   = pMin.x;
00228                         rod.y1   = pMin.y;
00229                         rod.x2   = pMax.x;
00230                         rod.y2   = pMax.y;
00231                         modified = true;
00232                 }
00233         }
00234         rod.x1 += srcRodCorner.x;
00235         rod.y1 += srcRodCorner.y;
00236         rod.x2 += srcRodCorner.x;
00237         rod.y2 += srcRodCorner.y;
00238         return modified;
00239 }
00240 
00241 void LensDistortPlugin::getRegionsOfInterest( const OFX::RegionsOfInterestArguments& args, OFX::RegionOfInterestSetter& rois )
00242 {
00243         OfxRectD srcRod = _clipSrc->getCanonicalRod( args.time );
00244         OfxRectD dstRod = _clipDst->getCanonicalRod( args.time );
00245 
00246         LensDistortProcessParams<Scalar> params;
00247         terry::sampler::EParamFilter interpolation = getInterpolation();
00248         if( _srcRefClip->isConnected() )
00249         {
00250                 OfxRectD srcRefRod = _srcRefClip->getCanonicalRod( args.time );
00251                 params = getProcessParams( srcRod, dstRod, srcRefRod, _clipDst->getPixelAspectRatio() );
00252         }
00253         else
00254         {
00255                 params = getProcessParams( srcRod, dstRod, _clipDst->getPixelAspectRatio() );
00256         }
00257 
00258         OfxRectD outputRoi = args.regionOfInterest;
00259         outputRoi.x1 -= dstRod.x1; // to dest rod coordinates
00260         outputRoi.y1 -= dstRod.y1;
00261         outputRoi.x2 -= dstRod.x1;
00262         outputRoi.y2 -= dstRod.y1;
00263         OfxRectD srcRoi = transformValues( getLensType(), params, outputRoi );
00264         srcRoi.x1    += srcRod.x1; // to RoW coordinates
00265         srcRoi.y1    += srcRod.y1;
00266         srcRoi.x2    += srcRod.x1;
00267         srcRoi.y2    += srcRod.y1;
00268         outputRoi.x1 += dstRod.x1; // to RoW coordinates
00269         outputRoi.y1 += dstRod.y1;
00270         outputRoi.x2 += dstRod.x1;
00271         outputRoi.y2 += dstRod.y1;
00272 
00273         // add margin around depending on interpolation region sizes
00274         double margin = 0.0;
00275         switch( interpolation )
00276         {
00277                 case terry::sampler::eParamFilterNearest:
00278                 case terry::sampler::eParamFilterBilinear:
00279                 {
00280                         margin = 1.0; // one pixel margin
00281                         break;
00282                 }
00283                 case terry::sampler::eParamFilterBicubic:
00284                 case terry::sampler::eParamFilterBC:
00285                 case terry::sampler::eParamFilterCatrom:
00286                 case terry::sampler::eParamFilterMitchell:
00287                 case terry::sampler::eParamFilterParzen:
00288                 case terry::sampler::eParamFilterKeys:
00289                 case terry::sampler::eParamFilterSimon:
00290                 case terry::sampler::eParamFilterRifman:
00291                 {
00292                         margin = 2.0; // two pixels margin
00293                         break;
00294                 }
00295                 case terry::sampler::eParamFilterLanczos:
00296                 case terry::sampler::eParamFilterLanczos3:
00297                 case terry::sampler::eParamFilterLanczos4:
00298                 case terry::sampler::eParamFilterLanczos6:
00299                 case terry::sampler::eParamFilterLanczos12:
00300                 case terry::sampler::eParamFilterGaussian:
00301                 {
00302                         margin = 6.0;
00303                         break;
00304                 }
00305         }
00306         srcRoi.x1 -= margin;
00307         srcRoi.y1 -= margin;
00308         srcRoi.x2 += margin;
00309         srcRoi.y2 += margin;
00310 
00311         //    srcRoi.x1 += 2; // if we remove 2 pixels to the needed RoI the plugin crash, because it tries to access to this pixels
00312         //    srcRoi.y1 += 2; // so the calculation of the RoI has a precision of one pixel
00313         //    srcRoi.x2 -= 2;
00314         //    srcRoi.y2 -= 2;
00315         OfxRectD srcRealRoi = rectanglesIntersection( srcRoi, srcRod );
00316 
00317         rois.setRegionOfInterest( *_clipSrc, srcRealRoi );
00318 
00319         if( _debugDisplayRoi->getValue() )
00320         {
00321                 _srcRealRoi = srcRealRoi;
00322                 _srcRoi     = srcRoi;
00323                 _dstRoi     = outputRoi;
00324         }
00325 }
00326 
00327 LensDistortProcessParams<LensDistortPlugin::Scalar> LensDistortPlugin::getProcessParams( const OfxRectD& inputRod, const OfxRectD& outputRod, const OfxRectD& optionalInputRod, const double pixelAspectRatio, const bool reverse ) const
00328 {
00329         const bool      useOptionalInputRod  = ( optionalInputRod.x1 != optionalInputRod.x2 ) && ( optionalInputRod.y1 != optionalInputRod.y2 );
00330         const OfxRectD& choosedInputRod      = useOptionalInputRod ? optionalInputRod : inputRod;
00331 
00332         typedef     bgil::point2<Scalar> Point2;
00333         LensDistortProcessParams<Scalar> params;
00334 
00335         double preScale         = _preScale->getValue();
00336         double postScale        = _postScale->getValue();
00337 
00338         params._coef1           = _coef1->getValue();
00339 
00340         if( params._coef1 >= 0 )
00341                 params._distort = true; // distort
00342         else
00343                 params._distort = false; // undistort
00344 
00345         params._coef1           = std::abs( params._coef1 );
00346         params._coef2           = _coef2->getValue();
00347         params._squeeze         = _squeeze->getValue();
00348         params._asymmetric      = ofxToGil( _asymmetric->getValue() );
00349 
00350         params._preScale.x      = ( 1.0 / preScale );
00351         params._preScale.y      = 1.0 / preScale;
00352 
00353         params._postScale.x     = ( 1.0 / postScale );
00354         params._postScale.y     = 1.0 / postScale;
00355 
00356         Point2  imgShift        = Point2( inputRod.x1 - outputRod.x1, inputRod.y1 - outputRod.y1 ); // translate output -> source
00357         params._imgSizeSrc      = Point2( choosedInputRod.x2 - choosedInputRod.x1, choosedInputRod.y2 - choosedInputRod.y1 );
00358         params._imgCenterSrc    = Point2( params._imgSizeSrc.x * 0.5, params._imgSizeSrc.y * 0.5 );
00359         params._imgCenterDst    = params._imgCenterSrc + imgShift;
00360         params._imgHalfDiagonal = std::sqrt( params._imgCenterSrc.x * params._imgCenterSrc.x * pixelAspectRatio * pixelAspectRatio + params._imgCenterSrc.y * params._imgCenterSrc.y );
00361         params._pixelRatio      = pixelAspectRatio;
00362 
00363         switch( getCenterType() )
00364         {
00365                 case eParamCenterTypeSource:
00366                 {
00367                         params._lensCenterSrc = pointNormalizedXXcToCanonicalXY( ofxToGil( _center->getValue() ), params._imgSizeSrc );
00368                         if( useOptionalInputRod )
00369                         {
00370                                 Point2 imgShiftBetweenInputs = Point2( optionalInputRod.x1 - inputRod.x1, optionalInputRod.y1 - inputRod.y1 ); // translate inputRod -> optionalInputRod
00371                                 params._lensCenterSrc += imgShiftBetweenInputs;
00372                         }
00373                         params._lensCenterDst = params._lensCenterSrc + imgShift;
00374                         break;
00375                 }
00376                 case eParamCenterTypeRoW:
00377                 {
00378                         // we can't place in RoW because we don't have the RoW size...
00379                         break;
00380                 }
00381         }
00382         if( _reverse->getValue() != reverse )
00383         {
00384                 Point2 swapPreScale = params._preScale;
00385 
00386                 params._distort   = !params._distort;
00387                 params._preScale  = 1.0 / params._postScale;
00388                 params._postScale = 1.0 / swapPreScale;
00389         }
00390         return params;
00391 }
00392 
00393 LensDistortParams LensDistortPlugin::getProcessParams(  ) const
00394 {
00395         LensDistortParams lensDistortParams;
00396         SamplerPlugin::fillProcessParams( lensDistortParams._samplerProcessParams );
00397 
00398         lensDistortParams._lensType          = (tuttle::plugin::lens::EParamLensType)   _lensType        -> getValue();
00399         lensDistortParams._centerType        = (tuttle::plugin::lens::EParamCenterType) _centerType      -> getValue();
00400 
00401         return lensDistortParams;
00402 }
00403 
00404 }
00405 }
00406 }
00407