예제 #1
0
void
TrackArgs::getRedrawAreasNeeded(TimeValue time,
                                std::list<RectD>* canonicalRects) const
{
    for (std::vector<TrackMarkerAndOptionsPtr >::const_iterator it = _imp->tracks.begin(); it != _imp->tracks.end(); ++it) {
        if ( !(*it)->natronMarker->isEnabled(time) ) {
            continue;
        }
        KnobDoublePtr searchBtmLeft = (*it)->natronMarker->getSearchWindowBottomLeftKnob();
        KnobDoublePtr searchTopRight = (*it)->natronMarker->getSearchWindowTopRightKnob();
        KnobDoublePtr centerKnob = (*it)->natronMarker->getCenterKnob();
        KnobDoublePtr offsetKnob = (*it)->natronMarker->getOffsetKnob();
        Point offset, center, btmLeft, topRight;
        offset.x = offsetKnob->getValueAtTime(time, DimIdx(0));
        offset.y = offsetKnob->getValueAtTime(time, DimIdx(1));

        center.x = centerKnob->getValueAtTime(time, DimIdx(0));
        center.y = centerKnob->getValueAtTime(time, DimIdx(1));

        btmLeft.x = searchBtmLeft->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
        btmLeft.y = searchBtmLeft->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;

        topRight.x = searchTopRight->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
        topRight.y = searchTopRight->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;

        RectD rect;
        rect.x1 = btmLeft.x;
        rect.y1 = btmLeft.y;
        rect.x2 = topRight.x;
        rect.y2 = topRight.y;
        canonicalRects->push_back(rect);
    }
}
예제 #2
0
RectI
TrackMarker::getMarkerImageRoI(int time) const
{
    const unsigned int mipmapLevel = 0;
    Point center, offset;
    KnobDoublePtr centerKnob = getCenterKnob();
    KnobDoublePtr offsetKnob = getOffsetKnob();

    center.x = centerKnob->getValueAtTime(time, 0);
    center.y = centerKnob->getValueAtTime(time, 1);

    offset.x = offsetKnob->getValueAtTime(time, 0);
    offset.y = offsetKnob->getValueAtTime(time, 1);

    RectD roiCanonical;
    KnobDoublePtr swBl = getSearchWindowBottomLeftKnob();
    KnobDoublePtr swTr = getSearchWindowTopRightKnob();

    roiCanonical.x1 = swBl->getValueAtTime(time, 0) + center.x + offset.x;
    roiCanonical.y1 = swBl->getValueAtTime(time, 1) + center.y + offset.y;
    roiCanonical.x2 = swTr->getValueAtTime(time, 0) + center.x + offset.x;
    roiCanonical.y2 = swTr->getValueAtTime(time, 1) + center.y + offset.y;

    RectI roi;
    NodePtr node = getContext()->getNode();
    NodePtr input = node->getInput(0);
    if (!input) {
        return RectI();
    }
    roiCanonical.toPixelEnclosing(mipmapLevel, input ? input->getEffectInstance()->getAspectRatio(-1) : 1., &roi);

    return roi;
}
예제 #3
0
bool
CornerPinOverlayInteract::onOverlayPenUp(TimeValue time,
                                         const RenderScale & /*renderScale*/,
                                         ViewIdx view,
                                         const QPointF & /*viewportPos*/,
                                         const QPointF & /*pos*/,
                                         double /*pressure*/,
                                         TimeValue /*timestamp*/)
{
    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    KnobDoublePtr from1Knob = _imp->from[0].lock();

    if ( !from1Knob || !from1Knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    bool didSomething = _imp->dragging != -1;

    if ( !_imp->interactiveDrag && (_imp->dragging != -1) ) {
        // no need to redraw overlay since it is slave to the paramaters
        if (_imp->useFromDrag) {
            KnobDoublePtr knob = _imp->from[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = _imp->fromDrag[_imp->dragging].x;
            val[1] = _imp->fromDrag[_imp->dragging].y;
            knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
        } else {
            KnobDoublePtr knob = _imp->to[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = _imp->toDrag[_imp->dragging].x;
            val[1] = _imp->toDrag[_imp->dragging].y;

            if (_imp->toPointsAutoKeyingEnabled) {
                knob->setValueAtTimeAcrossDimensions(time, val, DimIdx(0), view, eValueChangedReasonUserEdited);

                // Also set a keyframe on other points
                for (int i = 0; i < 4; ++i) {
                    if (i == _imp->dragging) {
                        continue;
                    }
                    std::vector<double> values(2);
                    KnobDoublePtr toPoint = _imp->to[i].lock();
                    values[0] = toPoint->getValueAtTime(time, DimIdx(0));
                    values[1] = toPoint->getValueAtTime(time, DimIdx(1));
                    toPoint->setValueAtTimeAcrossDimensions(time, values, DimIdx(0), view, eValueChangedReasonUserEdited);
                }
            } else {
                knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
            }
        }
    }
    _imp->dragging = -1;

    return didSomething;
} // onOverlayPenUp
예제 #4
0
void
TrackMarker::setKeyFrameOnCenterAndPatternAtTime(int time)
{
    KnobDoublePtr center = _imp->center.lock();

    for (int i = 0; i < center->getDimension(); ++i) {
        double v = center->getValueAtTime(time, i);
        center->setValueAtTime(time, v, ViewSpec::all(), i);
    }

    KnobDoublePtr patternCorners[4] = {_imp->patternBtmLeft.lock(), _imp->patternTopLeft.lock(), _imp->patternTopRight.lock(), _imp->patternBtmRight.lock()};
    for (int c = 0; c < 4; ++c) {
        KnobDoublePtr k = patternCorners[c];
        for (int i = 0; i < k->getDimension(); ++i) {
            double v = k->getValueAtTime(time, i);
            k->setValueAtTime(time, v, ViewSpec::all(), i);
        }
    }
}
예제 #5
0
    void getTo(TimeValue time,
               int index,
               double* tx,
               double* ty) const
    {
        KnobDoublePtr knob = to[index].lock();

        assert(knob);
        *tx = knob->getValueAtTime(time, DimIdx(0));
        *ty = knob->getValueAtTime(time, DimIdx(1));
    }
예제 #6
0
void
TrackMarker::setKeyFrameOnCenterAndPatternAtTime(TimeValue time)
{
    KnobDoublePtr center = _imp->center.lock();

    {
        std::vector<double> values(2);
        values[0] = center->getValueAtTime(time);
        values[1] = center->getValueAtTime(time, DimIdx(1));
        center->setValueAtTimeAcrossDimensions(time, values);
    }

    KnobDoublePtr patternCorners[4] = {_imp->patternBtmLeft.lock(), _imp->patternTopLeft.lock(), _imp->patternTopRight.lock(), _imp->patternBtmRight.lock()};
    for (int c = 0; c < 4; ++c) {
        KnobDoublePtr k = patternCorners[c];
        std::vector<double> values(2);
        values[0] = k->getValueAtTime(time, DimIdx(0));
        values[1] = k->getValueAtTime(time, DimIdx(1));
        k->setValueAcrossDimensions(values);
    }
}
예제 #7
0
RectD
TrackMarker::getMarkerImageRoI(TimeValue time) const
{
    Point center, offset;
    KnobDoublePtr centerKnob = getCenterKnob();
    KnobDoublePtr offsetKnob = getOffsetKnob();

    center.x = centerKnob->getValueAtTime(time, DimIdx(0));
    center.y = centerKnob->getValueAtTime(time, DimIdx(1));

    offset.x = offsetKnob->getValueAtTime(time, DimIdx(0));
    offset.y = offsetKnob->getValueAtTime(time, DimIdx(1));

    RectD roiCanonical;
    KnobDoublePtr swBl = getSearchWindowBottomLeftKnob();
    KnobDoublePtr swTr = getSearchWindowTopRightKnob();

    roiCanonical.x1 = swBl->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
    roiCanonical.y1 = swBl->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;
    roiCanonical.x2 = swTr->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
    roiCanonical.y2 = swTr->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;

    return roiCanonical;
}
예제 #8
0
파일: BaseTest.cpp 프로젝트: Kthulhu/Natron
TEST_F(BaseTest, SetValues)
{
    NodePtr generator = createNode(_generatorPluginID);

    assert(generator);
    KnobIPtr knob = generator->getKnobByName("noiseZSlope");
    KnobDoublePtr radius = boost::dynamic_pointer_cast<KnobDouble>(knob);
    EXPECT_TRUE(radius != 0);
    if (!radius) {
        return;
    }
    radius->setValue(0.5);
    EXPECT_TRUE(radius->getValue() == 0.5);

    //Check that linear interpolation is working as intended
    KeyFrame kf;
    radius->setInterpolationAtTime(eCurveChangeReasonInternal, ViewSpec::all(),  0, 0, eKeyframeTypeLinear, &kf);
    radius->setValueAtTime(0, 0., ViewSpec::all(), 0);
    radius->setValueAtTime(100, 1., ViewSpec::all(), 0);
    for (int i = 0; i <= 100; ++i) {
        double v = radius->getValueAtTime(i);
        EXPECT_TRUE(std::abs(v - i / 100.) < 1e-6);
    }
}
예제 #9
0
void
TrackerHelper::trackMarkers(const std::list<TrackMarkerPtr >& markers,
                             TimeValue start,
                             TimeValue end,
                             TimeValue frameStep,
                            const ViewerNodePtr& viewer)
{
    if ( markers.empty() ) {
        Q_EMIT trackingFinished();
        return;
    }

    TrackerParamsProviderPtr provider = _imp->provider.lock();
    if (!provider) {
        Q_EMIT trackingFinished();
        return;
    }

    NodePtr trackerNode = provider->getTrackerNode();
    if (!trackerNode) {
        Q_EMIT trackingFinished();
        return;
    }

    if (trackerNode->hasMandatoryInputDisconnected()) {
        Q_EMIT trackingFinished();
        return;
    }



    // The channels we are going to use for tracking
    bool enabledChannels[3];
    provider->getTrackChannels(&enabledChannels[0], &enabledChannels[1], &enabledChannels[2]);


    double formatWidth, formatHeight;
    Format f;
    trackerNode->getApp()->getProject()->getProjectDefaultFormat(&f);
    formatWidth = f.width();
    formatHeight = f.height();

    bool autoKeyingOnEnabledParamEnabled = provider->canDisableMarkersAutomatically();

    /// The accessor and its cache is local to a track operation, it is wiped once the whole sequence track is finished.
    boost::shared_ptr<TrackerFrameAccessor> accessor( new TrackerFrameAccessor(trackerNode, enabledChannels, formatHeight) );
    boost::shared_ptr<mv::AutoTrack> trackContext( new mv::AutoTrack( accessor.get() ) );
    std::vector<TrackMarkerAndOptionsPtr > trackAndOptions;
    mv::TrackRegionOptions mvOptions;
    /*
     Get the global parameters for the LivMV track: pre-blur sigma, No iterations, normalized intensities, etc...
     */
    _imp->beginLibMVOptionsForTrack(&mvOptions);

    /*
     For the given markers, do the following:
     - Get the "User" keyframes that have been set and create a LibMV marker for each keyframe as well as for the "start" time
     - Set the "per-track" parameters that were given by the user, that is the mv::TrackRegionOptions
     - t->mvMarker will contain the marker that evolves throughout the tracking
     */
    int trackIndex = 0;
    for (std::list<TrackMarkerPtr >::const_iterator it = markers.begin(); it != markers.end(); ++it, ++trackIndex) {

        if (autoKeyingOnEnabledParamEnabled) {
            (*it)->setEnabledAtTime(start, true);
        }

        TrackMarkerAndOptionsPtr t(new TrackMarkerAndOptions);
        t->natronMarker = *it;

        int mode_i = (*it)->getMotionModelKnob()->getValue();
        mvOptions.mode = motionModelIndexToLivMVMode(mode_i);

        // Set a keyframe on the marker to initialize its position
        {
            KnobDoublePtr centerKnob = (*it)->getCenterKnob();
            std::vector<double> values(2);
            values[0] = centerKnob->getValueAtTime(start, DimIdx(0));
            values[1] = centerKnob->getValueAtTime(start, DimIdx(1));
            centerKnob->setValueAtTimeAcrossDimensions(start, values);
        }

        // For a translation warp, we do not need to add an animation curve for the pattern which stays constant.
        if (mvOptions.mode != libmv::TrackRegionOptions::TRANSLATION) {
            KnobDoublePtr patternCorners[4];
            patternCorners[0] = (*it)->getPatternBtmLeftKnob();
            patternCorners[1] = (*it)->getPatternBtmRightKnob();
            patternCorners[2] = (*it)->getPatternTopRightKnob();
            patternCorners[3] = (*it)->getPatternTopLeftKnob();
            for (int c = 0; c < 4; ++c) {
                KnobDoublePtr k = patternCorners[c];
                std::vector<double> values(2);
                values[0] = k->getValueAtTime(start, DimIdx(0));
                values[1] = k->getValueAtTime(start, DimIdx(1));
                k->setValueAcrossDimensions(values);
            }
        }

        std::set<double> userKeys;
        t->natronMarker->getMasterKeyFrameTimes(ViewIdx(0), &userKeys);

        if ( userKeys.empty() ) {
            // Set a user keyframe on tracking start if the marker does not have any user keys
            t->natronMarker->setKeyFrame(start, ViewSetSpec(0), 0);
        }

        PreviouslyTrackedFrameSet previousFramesOrdered;

        // Make sure to create a marker at the start time
        userKeys.insert(start);


        // Add a libmv marker for all keyframes
        for (std::set<double>::iterator it2 = userKeys.begin(); it2 != userKeys.end(); ++it2) {

            // Add the marker to the markers ordered only if it can contribute to predicting its next position
            if ( ( (frameStep > 0) && (*it2 <= start) ) || ( (frameStep < 0) && (*it2 >= start) ) ) {
                previousFramesOrdered.insert( PreviouslyComputedTrackFrame(TimeValue(*it2), true) );
            }
        }


        //For all already tracked frames which are not keyframes, add them to the AutoTrack too
        std::set<double> centerKeys;
        t->natronMarker->getCenterKeyframes(&centerKeys);

        for (std::set<double>::iterator it2 = centerKeys.begin(); it2 != centerKeys.end(); ++it2) {
            if ( userKeys.find(*it2) != userKeys.end() ) {
                continue;
            }

            // Add the marker to the markers ordered only if it can contribute to predicting its next position
            if ( ( ( (frameStep > 0) && (*it2 < start) ) || ( (frameStep < 0) && (*it2 > start) ) ) ) {
                previousFramesOrdered.insert( PreviouslyComputedTrackFrame(TimeValue(*it2), false) );
            }
        }


        // Taken from libmv, only initialize the filter to this amount of frames (max)
        const int max_frames_to_predict_from = 20;
        std::list<mv::Marker> previouslyComputedMarkersOrdered;

        // Find the first keyframe that's not considered to go before start or end
        PreviouslyTrackedFrameSet::iterator prevFramesIt = previousFramesOrdered.lower_bound(PreviouslyComputedTrackFrame(start, false));
        if (frameStep < 0) {
            if (prevFramesIt != previousFramesOrdered.end()) {
                while (prevFramesIt != previousFramesOrdered.end() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) {

                    mv::Marker mvMarker;

                    TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker);
                    trackContext->AddMarker(mvMarker);

                    // insert in the front of the list so that the order is reversed
                    previouslyComputedMarkersOrdered.push_front(mvMarker);
                    ++prevFramesIt;
                }
            }
            // previouslyComputedMarkersOrdered is now ordererd by decreasing order
        } else {

            if (prevFramesIt != previousFramesOrdered.end()) {
                while (prevFramesIt != previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) {

                    mv::Marker mvMarker;

                    TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker);
                    trackContext->AddMarker(mvMarker);

                    // insert in the front of the list so that the order is reversed
                    previouslyComputedMarkersOrdered.push_front(mvMarker);
                    --prevFramesIt;
                }
                if (prevFramesIt == previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) {
                    mv::Marker mvMarker;

                    TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker);
                    trackContext->AddMarker(mvMarker);

                    // insert in the front of the list so that the order is reversed
                    previouslyComputedMarkersOrdered.push_front(mvMarker);

                }
            }
            // previouslyComputedMarkersOrdered is now ordererd by increasing order
        }


        // There must be at least 1 marker at the start time
        assert( !previouslyComputedMarkersOrdered.empty() );

        // Initialise the kalman state with the marker at the position

        std::list<mv::Marker>::iterator mIt = previouslyComputedMarkersOrdered.begin();
        t->mvState.Init(*mIt, frameStep);
        ++mIt;
        for (; mIt != previouslyComputedMarkersOrdered.end(); ++mIt) {
            mv::Marker predictedMarker;
            if ( !t->mvState.PredictForward(mIt->frame, &predictedMarker) ) {
                break;
            } else {
                t->mvState.Update(*mIt);
            }
        }


        t->mvOptions = mvOptions;
        trackAndOptions.push_back(t);
    }
    
    
    /*
     Launch tracking in the scheduler thread.
     */
    boost::shared_ptr<TrackArgs> args( new TrackArgs(start, end, frameStep, trackerNode->getApp()->getTimeLine(), viewer, trackContext, accessor, trackAndOptions, formatWidth, formatHeight, autoKeyingOnEnabledParamEnabled) );
    _imp->scheduler->track(args);
} // TrackerHelper::trackMarkers
예제 #10
0
bool
TrackMarkerPM::trackMarker(bool forward,
                           int refFrame,
                           int frame)
{
    KnobButtonPtr button;

    if (forward) {
        button = trackNextButton.lock();
    } else {
        button = trackPrevButton.lock();
    }
    KnobIntPtr refFrameK = refFrameKnob.lock();
    refFrameK->setValue(refFrame);

    // Unslave the center knob since the trackerNode will update it, then update the marker center
    KnobDoublePtr center = centerKnob.lock();
    center->unlink(DimSpec::all(), ViewSetSpec::all(), true);

    trackerNode->getEffectInstance()->onKnobValueChanged_public(button, eValueChangedReasonUserEdited, TimeValue(frame), ViewIdx(0));

    KnobDoublePtr markerCenter = getCenterKnob();
    // The TrackerPM plug-in has set a keyframe at the refFrame and frame, copy them
    bool ret = true;
    double centerPoint[2];
    for (int i = 0; i < center->getNDimensions(); ++i) {
        {
            int index = center->getKeyFrameIndex(ViewIdx(0), DimIdx(i), TimeValue(frame));
            if (index != -1) {
                centerPoint[i] = center->getValueAtTime(TimeValue(frame), DimIdx(i));
                markerCenter->setValueAtTime(TimeValue(frame), centerPoint[i], ViewSetSpec::all(), DimIdx(i));
            } else {
                // No keyframe at this time: tracking failed
                ret = false;
                break;
            }
        }
        {
            int index = center->getKeyFrameIndex(ViewIdx(0), DimIdx(i), TimeValue(refFrame));
            if (index != -1) {
                double value = center->getValueAtTime(TimeValue(refFrame), DimIdx(i));
                markerCenter->setValueAtTime(TimeValue(refFrame), value, ViewSetSpec::all(), DimIdx(i));
            }
        }
    }

    // Convert the correlation score of the TrackerPM to the error
    if (ret) {
        KnobDoublePtr markerError = getErrorKnob();
        KnobDoublePtr correlation = correlationScoreKnob.lock();
        {
            int index = correlation->getKeyFrameIndex(ViewIdx(0), DimIdx(0), TimeValue(frame));
            if (index != -1) {
                // The error is estimated as a percentage of the correlation across the number of pixels in the pattern window
                KnobDoublePtr  pBtmLeft = patternBtmLeftKnob.lock();
                KnobDoublePtr  pTopRight = patternTopRightKnob.lock();
                Point btmLeft, topRight;

                btmLeft.x = pBtmLeft->getValueAtTime(TimeValue(frame), DimIdx(0));
                btmLeft.y = pBtmLeft->getValueAtTime(TimeValue(frame), DimIdx(1));

                topRight.x = pTopRight->getValueAtTime(TimeValue(frame), DimIdx(0));
                topRight.y = pTopRight->getValueAtTime(TimeValue(frame), DimIdx(1));


                double areaPixels = (topRight.x - btmLeft.x) * (topRight.y - btmLeft.y);
                NodePtr trackerInput = trackerNode->getInput(0);
                if (trackerInput) {
                    ImagePlaneDesc comps, paireComps;
                    trackerInput->getEffectInstance()->getMetadataComponents(-1, &comps, &paireComps);
                    areaPixels *= comps.getNumComponents();
                }

                double value = correlation->getValueAtTime(TimeValue(frame), DimIdx(0));

                // Convert to a percentage
                if (areaPixels > 0) {
                    value /= areaPixels;
                }

                markerError->setValueAtTime(TimeValue(frame), value, ViewSetSpec::all(), DimIdx(0));
            }
        }
    }

    if ( !center->linkTo(markerCenter) ) {
        throw std::runtime_error("Could not link center");
    }

    return ret;
} // TrackMarkerPM::trackMarker
예제 #11
0
void
TrackerNodePrivate::solveTransformParams()
{
    setTransformOutOfDate(false);

    std::vector<TrackMarkerPtr> markers;

    knobsTable->getAllMarkers(&markers);
    if ( markers.empty() ) {
        return;
    }

    resetTransformParamsAnimation();

    KnobChoicePtr motionTypeKnob = motionType.lock();
    int motionType_i = motionTypeKnob->getValue();
    TrackerMotionTypeEnum type =  (TrackerMotionTypeEnum)motionType_i;
    TimeValue refTime(referenceFrame.lock()->getValue());
    int jitterPer = 0;
    bool jitterAdd = false;
    switch (type) {
        case eTrackerMotionTypeNone:

            return;
        case eTrackerMotionTypeMatchMove:
        case eTrackerMotionTypeStabilize:
            break;
        case eTrackerMotionTypeAddJitter:
        case eTrackerMotionTypeRemoveJitter: {
            jitterPer = jitterPeriod.lock()->getValue();
            jitterAdd = type == eTrackerMotionTypeAddJitter;
            break;
        }
    }

    setSolverParamsEnabled(false);

    std::set<TimeValue> keyframes;
    {
        for (std::size_t i = 0; i < markers.size(); ++i) {
            std::set<double> keys;
            markers[i]->getCenterKeyframes(&keys);
            for (std::set<double>::iterator it = keys.begin(); it != keys.end(); ++it) {
                keyframes.insert(TimeValue(*it));
            }
        }
    }
    KnobChoicePtr transformTypeKnob = transformType.lock();
    assert(transformTypeKnob);
    int transformType_i = transformTypeKnob->getValue();
    TrackerTransformNodeEnum transformType = (TrackerTransformNodeEnum)transformType_i;
    NodePtr node = publicInterface->getNode();

    invertTransform.lock()->setValue(type == eTrackerMotionTypeStabilize);

    KnobDoublePtr centerKnob = center.lock();

    // Set the center at the reference frame
    Point centerValue = {0, 0};
    int nSamplesAtRefTime = 0;
    for (std::size_t i = 0; i < markers.size(); ++i) {
        if ( !markers[i]->isEnabled(refTime) ) {
            continue;
        }
        KnobDoublePtr markerCenterKnob = markers[i]->getCenterKnob();

        centerValue.x += markerCenterKnob->getValueAtTime(refTime);
        centerValue.y += markerCenterKnob->getValueAtTime(refTime, DimIdx(1));
        ++nSamplesAtRefTime;
    }
    if (nSamplesAtRefTime) {
        centerValue.x /= nSamplesAtRefTime;
        centerValue.y /= nSamplesAtRefTime;
        {
            std::vector<double> values(2);
            values[0] = centerValue.x;
            values[1] = centerValue.y;
            centerKnob->setValueAcrossDimensions(values);
        }

    }

    bool robust;
    robust = robustModel.lock()->getValue();

    KnobDoublePtr maxFittingErrorKnob = fittingErrorWarnIfAbove.lock();
    const double maxFittingError = maxFittingErrorKnob->getValue();

    node->getApp()->progressStart( node, tr("Solving for transform parameters...").toStdString(), std::string() );

    lastSolveRequest.refTime = refTime;
    lastSolveRequest.jitterPeriod = jitterPer;
    lastSolveRequest.jitterAdd = jitterAdd;
    lastSolveRequest.allMarkers = markers;
    lastSolveRequest.keyframes = keyframes;
    lastSolveRequest.robustModel = robust;
    lastSolveRequest.maxFittingError = maxFittingError;

    switch (transformType) {
        case eTrackerTransformNodeTransform:
            computeTransformParamsFromTracks();
            break;
        case eTrackerTransformNodeCornerPin:
            computeCornerParamsFromTracks();
            break;
    }
} // TrackerNodePrivate::solveTransformParams
예제 #12
0
bool
RotoShapeRenderNodePrivate::renderStroke_generic(RenderStrokeDataPtr userData,
                                                 PFNRenderStrokeBeginRender beginCallback,
                                                 PFNRenderStrokeRenderDot renderDotCallback,
                                                 PFNRenderStrokeEndRender endCallback,
                                                 const std::list<std::list<std::pair<Point, double> > >& strokes,
                                                 const double distToNextIn,
                                                 const Point& lastCenterPointIn,
                                                 const RotoDrawableItemPtr& stroke,
                                                 bool doBuildup,
                                                 double opacity,
                                                 TimeValue time,
                                                 ViewIdx /*view*/,
                                                 const RenderScale& scale,
                                                 double* distToNextOut,
                                                 Point* lastCenterPoint)
{
    assert(distToNextOut && lastCenterPoint);
    *distToNextOut = 0;

    double brushSize, brushSizePixelX, brushSizePixelY, brushSpacing, brushHardness, writeOnStart, writeOnEnd;
    bool pressureAffectsOpacity, pressureAffectsHardness, pressureAffectsSize;
    {
        KnobDoublePtr brushSizeKnob = stroke->getBrushSizeKnob();
        brushSize = brushSizeKnob->getValueAtTime(time);
        KnobDoublePtr brushSpacingKnob = stroke->getBrushSpacingKnob();
        brushSpacing = brushSpacingKnob->getValueAtTime(time);
        if (brushSpacing == 0.) {
            return false;
        }
        brushSpacing = std::max(brushSpacing, 0.05);



        KnobDoublePtr brushHardnessKnob = stroke->getBrushHardnessKnob();
        brushHardness = brushHardnessKnob->getValueAtTime(time);
        KnobDoublePtr visiblePortionKnob = stroke->getBrushVisiblePortionKnob();
        writeOnStart = visiblePortionKnob->getValueAtTime(time);
        writeOnEnd = visiblePortionKnob->getValueAtTime(time, DimIdx(1));
        if ( (writeOnEnd - writeOnStart) <= 0. ) {
            return false;
        }


        // This function is also used for opened bezier which do not have pressure.
        RotoStrokeItemPtr isStroke = toRotoStrokeItem(stroke);
        if (!isStroke) {
            pressureAffectsOpacity = false;
            pressureAffectsSize = false;
            pressureAffectsHardness = false;
        } else {
            KnobBoolPtr pressureOpacityKnob = isStroke->getPressureOpacityKnob();
            KnobBoolPtr pressureSizeKnob = isStroke->getPressureSizeKnob();
            KnobBoolPtr pressureHardnessKnob = isStroke->getPressureHardnessKnob();
            pressureAffectsOpacity = pressureOpacityKnob->getValueAtTime(time);
            pressureAffectsSize = pressureSizeKnob->getValueAtTime(time);
            pressureAffectsHardness = pressureHardnessKnob->getValueAtTime(time);
        }
        brushSizePixelX = brushSize;
        brushSizePixelY = brushSizePixelX;

        brushSizePixelX = std::max( 1., brushSizePixelX * scale.x);
        brushSizePixelY = std::max( 1., brushSizePixelY * scale.y);
    }

    double distToNext = distToNextIn;

    bool hasRenderedDot = false;
    beginCallback(userData, brushSizePixelX, brushSizePixelY, brushSpacing, brushHardness, pressureAffectsOpacity, pressureAffectsHardness, pressureAffectsSize, doBuildup, opacity);


    *lastCenterPoint = lastCenterPointIn;
    Point prevCenter = lastCenterPointIn;
    for (std::list<std::list<std::pair<Point, double> > >::const_iterator strokeIt = strokes.begin(); strokeIt != strokes.end(); ++strokeIt) {
        int firstPoint = (int)std::floor( (strokeIt->size() * writeOnStart) );
        int endPoint = (int)std::ceil( (strokeIt->size() * writeOnEnd) );
        assert( firstPoint >= 0 && firstPoint < (int)strokeIt->size() && endPoint > firstPoint && endPoint <= (int)strokeIt->size() );


        ///The visible portion of the paint's stroke with points adjusted to pixel coordinates
        std::list<std::pair<Point, double> > visiblePortion;
        std::list<std::pair<Point, double> >::const_iterator startingIt = strokeIt->begin();
        std::list<std::pair<Point, double> >::const_iterator endingIt = strokeIt->begin();
        std::advance(startingIt, firstPoint);
        std::advance(endingIt, endPoint);
        for (std::list<std::pair<Point, double> >::const_iterator it = startingIt; it != endingIt; ++it) {
            visiblePortion.push_back(*it);
        }
        if ( visiblePortion.empty() ) {
            continue;
        }

        std::list<std::pair<Point, double> >::iterator it = visiblePortion.begin();

        if (visiblePortion.size() == 1) {
            double spacing;
            *lastCenterPoint = it->first;
            renderDotCallback(userData, prevCenter, *lastCenterPoint, it->second, &spacing);
            distToNext += spacing;
            continue;
        }

        //prevCenter = it->first;

        std::list<std::pair<Point, double> >::iterator next = it;
        ++next;

        while ( next != visiblePortion.end() ) {
            //Render for each point a dot. Spacing is a percentage of brushSize:
            //Spacing at 1 means no dot is overlapping another (so the spacing is in fact brushSize)
            //Spacing at 0 we do not render the stroke
            double dx = next->first.x - it->first.x;
            double dy = next->first.y - it->first.y;

            // This is the distance between the current and next discretized points
            // Since the distance between each points may vary, we uniformly position a dot along the segments
            double dist = std::sqrt(dx * dx + dy * dy);

            // while the next point can be drawn on this segment, draw a point and advance
            while (distToNext <= dist) {
                double a = dist == 0. ? 0. : distToNext / dist;
                lastCenterPoint->x = it->first.x * (1 - a) + next->first.x * a;
                lastCenterPoint->y = it->first.y * (1 - a) + next->first.y * a;
                double pressure = it->second * (1 - a) + next->second * a;

                // draw the dot
                double spacing;
                bool rendered = renderDotCallback(userData, prevCenter, *lastCenterPoint, pressure, &spacing);
                hasRenderedDot |= rendered;
                prevCenter = *lastCenterPoint;
                distToNext += spacing;
                /*if (rendered) {
                } else {
                    break;
                }*/
            }

            // go to the next segment
            distToNext -= dist;
            ++next;
            ++it;
        }
    }

    endCallback(userData);

    *distToNextOut = distToNext;

    return hasRenderedDot;
}
예제 #13
0
bool
CornerPinOverlayInteract::onOverlayPenMotion(TimeValue time,
                                             const RenderScale & /*renderScale*/,
                                             ViewIdx view,
                                             const QPointF & /*viewportPos*/,
                                             const QPointF & penPos,
                                             double /*pressure*/,
                                             TimeValue /*timestamp*/)
{
    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    KnobDoublePtr from1Knob = _imp->from[0].lock();

    if ( !from1Knob || !from1Knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    RenderScale pscale;
    getPixelScale(pscale.x, pscale.y);

    OfxPointD to[4];
    OfxPointD from[4];
    bool enable[4];
    bool useFrom;

    if (_imp->dragging == -1) {
        for (int i = 0; i < 4; ++i) {
            _imp->getFrom(time, i, &from[i].x, &from[i].y);
            _imp->getTo(time, i, &to[i].x, &to[i].y);
            enable[i] = _imp->getEnabled(time, i);
        }
        useFrom = _imp->getUseFromPoints(time);
    } else {
        for (int i = 0; i < 4; ++i) {
            to[i] = _imp->toDrag[i];
            from[i] = _imp->fromDrag[i];
            enable[i] = _imp->enableDrag[i];
        }
        useFrom = _imp->useFromDrag;
    }

    if (!useFrom && !_imp->areToPointsAnimated()) {
        return false;
    }

    OfxPointD p[4];
    OfxPointD q[4];
    int enableBegin = 4;
    int enableEnd = 0;
    for (int i = 0; i < 4; ++i) {
        if (enable[i]) {
            if (useFrom) {
                p[i] = from[i];
                q[i] = to[i];
            } else {
                q[i] = from[i];
                p[i] = to[i];
            }
            if (i < enableBegin) {
                enableBegin = i;
            }
            if (i + 1 > enableEnd) {
                enableEnd = i + 1;
            }
        }
    }
    bool didSomething = false;
    bool valuesChanged = false;
    OfxPointD delta;
    delta.x = penPos.x() - _imp->lastPenPos.x();
    delta.y = penPos.y() - _imp->lastPenPos.y();

    _imp->hovering = -1;

    for (int i = enableBegin; i < enableEnd; ++i) {
        if (enable[i]) {
            if (_imp->dragging == i) {
                if (useFrom) {
                    from[i].x += delta.x;
                    from[i].y += delta.y;
                    _imp->fromDrag[i] = from[i];
                } else {
                    to[i].x += delta.x;
                    to[i].y += delta.y;
                    _imp->toDrag[i] = to[i];
                }
                valuesChanged = true;
            } else if ( CornerPinOverlayInteractPrivate::isNearby(penPos, p[i].x, p[i].y, CornerPinOverlayInteractPrivate::pointTolerance(), pscale) ) {
                _imp->hovering = i;
                didSomething = true;
            }
        }
    }

    if ( (_imp->dragging != -1) && _imp->interactiveDrag && valuesChanged ) {
        // no need to redraw overlay since it is slave to the paramaters

        if (_imp->useFromDrag) {
            KnobDoublePtr knob = _imp->from[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = from[_imp->dragging].x;
            val[1] = from[_imp->dragging].y;
            knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
        } else {
            KnobDoublePtr knob = _imp->to[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = to[_imp->dragging].x;
            val[1] = to[_imp->dragging].y;

            if (_imp->toPointsAutoKeyingEnabled) {
                knob->setValueAtTimeAcrossDimensions(time, val, DimIdx(0), view, eValueChangedReasonUserEdited);

                // Also set a keyframe on other points
                for (int i = 0; i < 4; ++i) {
                    if (i == _imp->dragging) {
                        continue;
                    }
                    std::vector<double> values(2);
                    KnobDoublePtr toPoint = _imp->to[i].lock();
                    values[0] = toPoint->getValueAtTime(time, DimIdx(0));
                    values[1] = toPoint->getValueAtTime(time, DimIdx(1));
                    toPoint->setValueAtTimeAcrossDimensions(time, values, DimIdx(0), view, eValueChangedReasonUserEdited);
                }
            } else {
                knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
            }
        }
    }

    _imp->lastPenPos = penPos;
    
    return didSomething || valuesChanged;
} // onOverlayPenMotion
예제 #14
0
bool
PointOverlayInteract::onOverlayPenMotion(TimeValue time,
                                         const RenderScale & /*renderScale*/,
                                         ViewIdx view,
                                         const QPointF & /*viewportPos*/,
                                         const QPointF & penPos,
                                         double /*pressure*/,
                                         TimeValue /*timestamp*/)
{
    KnobDoublePtr knob = _imp->param.lock();

    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    if ( !knob || !knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    RenderScale pscale;
    getPixelScale(pscale.x, pscale.y);

    QPointF pos;
    if (_imp->state == ePositionInteractStatePicked) {
        pos = _imp->lastPenPos;
    } else {
        double p[2];
        for (int i = 0; i < 2; ++i) {
            p[i] = knob->getValueAtTime(time, DimIdx(i));
            if (knob->getValueIsNormalized(DimIdx(i)) != eValueIsNormalizedNone) {
                p[i] = knob->denormalize(DimIdx(i), time, p[i]);
            }
        }
        pos.setX(p[0]);
        pos.setY(p[1]);
    }

    bool didSomething = false;
    bool valuesChanged = false;

    switch (_imp->state) {
        case ePositionInteractStateInactive:
        case ePositionInteractStatePoised: {
            // are we in the box, become 'poised'
            PositionInteractState newState;
            if ( ( std::fabs( penPos.x() - pos.x() ) <= _imp->pointTolerance() * pscale.x) &&
                ( std::fabs( penPos.y() - pos.y() ) <= _imp->pointTolerance() * pscale.y) ) {
                newState = ePositionInteractStatePoised;
            } else {
                newState = ePositionInteractStateInactive;
            }

            if (_imp->state != newState) {
                // state changed, must redraw
                redraw();
            }
            _imp->state = newState;
            //}
            break;
        }

        case ePositionInteractStatePicked: {
            valuesChanged = true;
            break;
        }
    }
    didSomething = (_imp->state == ePositionInteractStatePoised) || (_imp->state == ePositionInteractStatePicked);

    if ( (_imp->state != ePositionInteractStateInactive) && _imp->interactiveDrag && valuesChanged ) {
        std::vector<double> p(2);
        p[0] = fround(_imp->lastPenPos.x(), pscale.x);
        p[1] = fround(_imp->lastPenPos.y(), pscale.y);
        for (int i = 0; i < 2; ++i) {
            if (knob->getValueIsNormalized(DimIdx(i)) != eValueIsNormalizedNone) {
                p[i] = knob->normalize(DimIdx(i), time, p[i]);
            }
        }


        knob->setValueAcrossDimensions(p, DimIdx(0), ViewSetSpec(view), eValueChangedReasonUserEdited);
    }

    _imp->lastPenPos = penPos;

    return (didSomething || valuesChanged);
} // onOverlayPenMotion
예제 #15
0
void
PointOverlayInteract::drawOverlay(TimeValue time,
                                  const RenderScale & /*renderScale*/,
                                  ViewIdx /*view*/)
{
    KnobDoublePtr knob = _imp->param.lock();

    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    if ( !knob || !knob->shouldDrawOverlayInteract()) {
        return;
    }

    ColorRgba<double> color;
    if ( !getOverlayColor(color.r, color.g, color.b) ) {
        color.r = color.g = color.b = 0.8;
    }


    RenderScale pscale;
    getPixelScale(pscale.x, pscale.y);

    float pR = 1.f;
    float pG = 1.f;
    float pB = 1.f;
    switch (_imp->state) {
        case ePositionInteractStateInactive:
            pR = (float)color.r; pG = (float)color.g; pB = (float)color.b; break;
        case ePositionInteractStatePoised:
            pR = 0.f; pG = 1.0f; pB = 0.0f; break;
        case ePositionInteractStatePicked:
            pR = 0.f; pG = 1.0f; pB = 0.0f; break;
    }

    QPointF pos;
    if (_imp->state == ePositionInteractStatePicked) {
        pos = _imp->lastPenPos;
    } else {
        double p[2];
        for (int i = 0; i < 2; ++i) {
            p[i] = knob->getValueAtTime(time, DimIdx(i));
            if (knob->getValueIsNormalized(DimIdx(i)) != eValueIsNormalizedNone) {
                p[i] = knob->denormalize(DimIdx(i), time, p[i]);
            }
        }
        pos.setX(p[0]);
        pos.setY(p[1]);
    }
    //glPushAttrib(GL_ALL_ATTRIB_BITS); // caller is responsible for protecting attribs
    GL_GPU::PointSize( (GLfloat)_imp->pointSize() );
    // Draw everything twice
    // l = 0: shadow
    // l = 1: drawing

    double w, h;
    getViewportSize(w, h);

    GLdouble projection[16];
    GL_GPU::GetDoublev( GL_PROJECTION_MATRIX, projection);
    OfxPointD shadow; // how much to translate GL_PROJECTION to get exactly one pixel on screen
    shadow.x = 2. / (projection[0] * w);
    shadow.y = 2. / (projection[5] * h);


    int fmHeight = getLastCallingViewport()->getWidgetFontHeight();
    for (int l = 0; l < 2; ++l) {
        // shadow (uses GL_PROJECTION)
        GL_GPU::MatrixMode(GL_PROJECTION);
        int direction = (l == 0) ? 1 : -1;
        // translate (1,-1) pixels
        GL_GPU::Translated(direction * shadow.x, -direction * shadow.y, 0);
        GL_GPU::MatrixMode(GL_MODELVIEW); // Modelview should be used on Nuke

        GL_GPU::Color3f(pR * l, pG * l, pB * l);
        GL_GPU::Begin(GL_POINTS);
        GL_GPU::Vertex2d( pos.x(), pos.y() );
        GL_GPU::End();
        getLastCallingViewport()->renderText(pos.x(), pos.y() - ( fmHeight + _imp->pointSize() ) * pscale.y, knob->getOriginalName(), pR*l, pG*l, pB*l, 1.);
    }

} // drawOverlay
예제 #16
0
bool
TrackMarkerPM::trackMarker(bool forward,
                           int refFrame,
                           int frame)
{
    KnobButtonPtr button;

    if (forward) {
        button = trackNextButton.lock();
    } else {
        button = trackPrevButton.lock();
    }
    KnobIntPtr refFrameK = refFrameKnob.lock();
    refFrameK->setValue(refFrame);

    // Unslave the center knob since the trackerNode will update it, then update the marker center
    KnobDoublePtr center = centerKnob.lock();
    for (int i = 0; i < center->getDimension(); ++i) {
        center->unSlave(i, true);
    }

    trackerNode->getEffectInstance()->onKnobValueChanged_public(button, eValueChangedReasonNatronInternalEdited, frame, ViewIdx(0),
                                                                true);

    KnobDoublePtr markerCenter = getCenterKnob();
    // The TrackerPM plug-in has set a keyframe at the refFrame and frame, copy them
    bool ret = true;
    double centerPoint[2];
    for (int i = 0; i < center->getDimension(); ++i) {
        {
            int index = center->getKeyFrameIndex(ViewSpec::current(), i, frame);
            if (index != -1) {
                centerPoint[i] = center->getValueAtTime(frame, i);
                markerCenter->setValueAtTime(frame, centerPoint[i], ViewSpec::current(), i);
            } else {
                // No keyframe at this time: tracking failed
                ret = false;
                break;
            }
        }
        {
            int index = center->getKeyFrameIndex(ViewSpec::current(), i, refFrame);
            if (index != -1) {
                double value = center->getValueAtTime(refFrame, i);
                markerCenter->setValueAtTime(refFrame, value, ViewSpec::current(), i);
            }
        }
    }

    // Convert the correlation score of the TrackerPM to the error
    if (ret) {
        KnobDoublePtr markerError = getErrorKnob();
        KnobDoublePtr correlation = correlationScoreKnob.lock();
        {
            int index = correlation->getKeyFrameIndex(ViewSpec::current(), 0, frame);
            if (index != -1) {
                // The error is estimated as a percentage of the correlation across the number of pixels in the pattern window
                KnobDoublePtr  pBtmLeft = patternBtmLeftKnob.lock();
                KnobDoublePtr  pTopRight = patternTopRightKnob.lock();
                Point btmLeft, topRight;

                btmLeft.x = pBtmLeft->getValueAtTime(frame, 0);
                btmLeft.y = pBtmLeft->getValueAtTime(frame, 1);

                topRight.x = pTopRight->getValueAtTime(frame, 0);
                topRight.y = pTopRight->getValueAtTime(frame, 1);


                double areaPixels = (topRight.x - btmLeft.x) * (topRight.y - btmLeft.y);
                NodePtr trackerInput = trackerNode->getInput(0);
                if (trackerInput) {
                    ImageComponents comps = trackerInput->getEffectInstance()->getComponents(-1);
                    areaPixels *= comps.getNumComponents();
                }

                double value = correlation->getValueAtTime(frame, 0);

                // Convert to a percentage
                value /= areaPixels;

                markerError->setValueAtTime(frame, value, ViewSpec::current(), 0);
            }
        }
    }

    for (int i = 0; i < center->getDimension(); ++i) {
        center->slaveTo(i, markerCenter, i);
    }

    return ret;
} // TrackMarkerPM::trackMarker