TuttleOFX
1
|
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