void TrackerNodePrivate::computeTransformParamsFromTracksEnd(double refTime, double maxFittingError, const QList<TransformData>& results) { QList<TransformData> validResults; for (QList<TransformData>::const_iterator it = results.begin(); it != results.end(); ++it) { if (it->valid) { validResults.push_back(*it); } } KnobIntPtr smoothKnob = smoothTransform.lock(); int smoothTJitter, smoothRJitter, smoothSJitter; smoothTJitter = smoothKnob->getValue(DimIdx(0)); smoothRJitter = smoothKnob->getValue(DimIdx(1)); smoothSJitter = smoothKnob->getValue(DimIdx(2)); KnobDoublePtr translationKnob = translate.lock(); KnobDoublePtr scaleKnob = scale.lock(); KnobDoublePtr rotationKnob = rotate.lock(); KnobDoublePtr fittingErrorKnob = fittingError.lock(); KnobStringPtr fittingWarningKnob = fittingErrorWarning.lock(); int halfTJitter = smoothTJitter / 2; int halfRJitter = smoothRJitter / 2; int halfSJitter = smoothSJitter / 2; translationKnob->blockValueChanges(); scaleKnob->blockValueChanges(); rotationKnob->blockValueChanges(); fittingErrorKnob->blockValueChanges(); std::list<KnobIPtr> animatedKnobsChanged; animatedKnobsChanged.push_back(translationKnob); animatedKnobsChanged.push_back(scaleKnob); animatedKnobsChanged.push_back(rotationKnob); animatedKnobsChanged.push_back(fittingErrorKnob); Curve tmpTXCurve, tmpTYCurve, tmpRotateCurve, tmpScaleCurve, tmpFittingErrorCurve; bool mustShowFittingWarn = false; for (QList<TransformData>::const_iterator itResults = validResults.begin(); itResults != validResults.end(); ++itResults) { const TransformData& dataAtTime = *itResults; { KeyFrame kf(dataAtTime.time, dataAtTime.rms); if (dataAtTime.rms >= maxFittingError) { mustShowFittingWarn = true; } tmpFittingErrorCurve.setOrAddKeyframe(kf); } if (!dataAtTime.hasRotationAndScale) { // no rotation or scale: simply extract the translation Point translation; if (smoothTJitter > 1) { TranslateData avgT; averageDataFunctor<QList<TransformData>::const_iterator, void, TranslateData>(validResults.begin(), validResults.end(), itResults, halfTJitter, 0, &avgT, 0); translation.x = avgT.p.x; translation.y = avgT.p.y; } else { translation.x = dataAtTime.translation.x; translation.y = dataAtTime.translation.y; } { KeyFrame kx(dataAtTime.time, translation.x); KeyFrame ky(dataAtTime.time, translation.y); tmpTXCurve.setOrAddKeyframe(kx); tmpTYCurve.setOrAddKeyframe(ky); } } else { double rot = 0; if (smoothRJitter > 1) { RotateData avgR; averageDataFunctor<QList<TransformData>::const_iterator, void, RotateData>(validResults.begin(), validResults.end(), itResults, halfRJitter, 0, &avgR, 0); rot = avgR.r; } else { rot = dataAtTime.rotation; } { KeyFrame k(dataAtTime.time, rot); tmpRotateCurve.setOrAddKeyframe(k); } double scale; if (smoothSJitter > 1) { ScaleData avgR; averageDataFunctor<QList<TransformData>::const_iterator, void, ScaleData>(validResults.begin(), validResults.end(), itResults, halfSJitter, 0, &avgR, 0); scale = avgR.s; } else { scale = dataAtTime.scale; } { KeyFrame k(dataAtTime.time, scale); tmpScaleCurve.setOrAddKeyframe(k); } Point translation; if (smoothTJitter > 1) { TranslateData avgT; averageDataFunctor<QList<TransformData>::const_iterator, void, TranslateData>(validResults.begin(), validResults.end(), itResults, halfTJitter, 0, &avgT, 0); translation.x = avgT.p.x; translation.y = avgT.p.y; } else { translation.x = dataAtTime.translation.x; translation.y = dataAtTime.translation.y; } { KeyFrame kx(dataAtTime.time, translation.x); KeyFrame ky(dataAtTime.time, translation.y); tmpTXCurve.setOrAddKeyframe(kx); tmpTYCurve.setOrAddKeyframe(ky); } } } // for all samples fittingWarningKnob->setSecret(!mustShowFittingWarn); fittingErrorKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpFittingErrorCurve, 0 /*offset*/, 0 /*range*/); translationKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpTXCurve, 0 /*offset*/, 0 /*range*/); translationKnob->cloneCurve(ViewIdx(0), DimIdx(1), tmpTYCurve, 0 /*offset*/, 0 /*range*/); rotationKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpRotateCurve, 0 /*offset*/, 0 /*range*/); scaleKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpScaleCurve, 0 /*offset*/, 0 /*range*/); scaleKnob->cloneCurve(ViewIdx(0), DimIdx(1), tmpScaleCurve, 0 /*offset*/, 0 /*range*/); for (std::list<KnobIPtr>::iterator it = animatedKnobsChanged.begin(); it != animatedKnobsChanged.end(); ++it) { (*it)->unblockValueChanges(); (*it)->evaluateValueChange(DimSpec::all(), TimeValue(refTime), ViewSetSpec::all(), eValueChangedReasonUserEdited); } endSolve(); } // TrackerNodePrivate::computeTransformParamsFromTracksEnd
void TrackerNodePrivate::computeCornerParamsFromTracksEnd(double refTime, double maxFittingError, const QList<CornerPinData>& results) { // Make sure we get only valid results QList<CornerPinData> validResults; for (QList<CornerPinData>::const_iterator it = results.begin(); it != results.end(); ++it) { if (it->valid) { validResults.push_back(*it); } } // Get all knobs that we are going to write to and block any value changes on them KnobIntPtr smoothCornerPinKnob = smoothCornerPin.lock(); int smoothJitter = smoothCornerPinKnob->getValue(); int halfJitter = smoothJitter / 2; KnobDoublePtr fittingErrorKnob = fittingError.lock(); KnobDoublePtr fromPointsKnob[4]; KnobDoublePtr toPointsKnob[4]; KnobBoolPtr enabledPointsKnob[4]; KnobStringPtr fittingWarningKnob = fittingErrorWarning.lock(); for (int i = 0; i < 4; ++i) { fromPointsKnob[i] = fromPoints[i].lock(); toPointsKnob[i] = toPoints[i].lock(); enabledPointsKnob[i] = enableToPoint[i].lock(); } std::list<KnobIPtr> animatedKnobsChanged; fittingErrorKnob->blockValueChanges(); animatedKnobsChanged.push_back(fittingErrorKnob); for (int i = 0; i < 4; ++i) { toPointsKnob[i]->blockValueChanges(); animatedKnobsChanged.push_back(toPointsKnob[i]); } // Get reference corner pin CornerPinPoints refFrom; for (int c = 0; c < 4; ++c) { refFrom.pts[c].x = fromPointsKnob[c]->getValueAtTime(TimeValue(refTime)); refFrom.pts[c].y = fromPointsKnob[c]->getValueAtTime(TimeValue(refTime), DimIdx(1)); } // Create temporary curves and clone the toPoint internal curves at once because setValueAtTime will be slow since it emits // signals to create keyframes in keyframeSet Curve tmpToPointsCurveX[4], tmpToPointsCurveY[4]; Curve tmpFittingErrorCurve; bool mustShowFittingWarn = false; for (QList<CornerPinData>::const_iterator itResults = validResults.begin(); itResults != validResults.end(); ++itResults) { const CornerPinData& dataAtTime = *itResults; // Add the error to the curve and check if we need to turn on the RMS warning { KeyFrame kf(dataAtTime.time, dataAtTime.rms); if (dataAtTime.rms >= maxFittingError) { mustShowFittingWarn = true; } tmpFittingErrorCurve.setOrAddKeyframe(kf); } if (smoothJitter <= 1) { for (int c = 0; c < 4; ++c) { Point toPoint; toPoint = TrackerHelper::applyHomography(refFrom.pts[c], dataAtTime.h); KeyFrame kx(dataAtTime.time, toPoint.x); KeyFrame ky(dataAtTime.time, toPoint.y); tmpToPointsCurveX[c].setOrAddKeyframe(kx); tmpToPointsCurveY[c].setOrAddKeyframe(ky); //toPoints[c]->setValuesAtTime(dataAtTime[i].time, toPoint.x, toPoint.y, ViewSpec::all(), eValueChangedReasonUserEdited); } } else { // Average to points before and after if using jitter CornerPinPoints avgTos; averageDataFunctor<QList<CornerPinData>::const_iterator, CornerPinPoints, CornerPinPoints>(validResults.begin(), validResults.end(), itResults, halfJitter, &refFrom, &avgTos, 0); for (int c = 0; c < 4; ++c) { KeyFrame kx(dataAtTime.time, avgTos.pts[c].x); KeyFrame ky(dataAtTime.time, avgTos.pts[c].y); tmpToPointsCurveX[c].setOrAddKeyframe(kx); tmpToPointsCurveY[c].setOrAddKeyframe(ky); } } // use jitter } // for each result // If user wants a post-smooth, apply it if (smoothJitter > 1) { int halfSmoothJitter = smoothJitter / 2; KeyFrameSet xSet[4], ySet[4]; KeyFrameSet newXSet[4], newYSet[4]; for (int c = 0; c < 4; ++c) { xSet[c] = tmpToPointsCurveX[c].getKeyFrames_mt_safe(); ySet[c] = tmpToPointsCurveY[c].getKeyFrames_mt_safe(); } for (int c = 0; c < 4; ++c) { for (KeyFrameSet::const_iterator it = xSet[c].begin(); it != xSet[c].end(); ++it) { double avg; averageDataFunctor<KeyFrameSet::const_iterator, void, double>(xSet[c].begin(), xSet[c].end(), it, halfSmoothJitter, 0, &avg, 0); KeyFrame k(*it); k.setValue(avg); newXSet[c].insert(k); } for (KeyFrameSet::const_iterator it = ySet[c].begin(); it != ySet[c].end(); ++it) { double avg; averageDataFunctor<KeyFrameSet::const_iterator, void, double>(ySet[c].begin(), ySet[c].end(), it, halfSmoothJitter, 0, &avg, 0); KeyFrame k(*it); k.setValue(avg); newYSet[c].insert(k); } } for (int c = 0; c < 4; ++c) { tmpToPointsCurveX[c].setKeyframes(newXSet[c], true); tmpToPointsCurveY[c].setKeyframes(newYSet[c], true); } } fittingWarningKnob->setSecret(!mustShowFittingWarn); fittingErrorKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpFittingErrorCurve, 0 /*offset*/, 0 /*range*/); for (int c = 0; c < 4; ++c) { toPointsKnob[c]->cloneCurve(ViewIdx(0), DimIdx(0), tmpToPointsCurveX[c], 0 /*offset*/, 0 /*range*/); toPointsKnob[c]->cloneCurve(ViewIdx(0), DimIdx(1), tmpToPointsCurveY[c], 0 /*offset*/, 0 /*range*/); } for (std::list<KnobIPtr>::iterator it = animatedKnobsChanged.begin(); it != animatedKnobsChanged.end(); ++it) { (*it)->unblockValueChanges(); (*it)->evaluateValueChange(DimSpec::all(), TimeValue(refTime), ViewSetSpec::all(), eValueChangedReasonUserEdited); } endSolve(); } // TrackerNodePrivate::computeCornerParamsFromTracksEnd