Esempio n. 1
0
void
ViewerDisplayScheduler::onRenderStopped(bool /*/aborted*/)
{
    // Refresh all previews in the tree
    NodePtr effect = getOutputNode();
    
    effect->getApp()->refreshAllPreviews();
    
    if ( effect->getApp()->isGuiFrozen() ) {
        getEngine()->s_refreshAllKnobs();
    }
}
Esempio n. 2
0
void
TrackerHelper::onSchedulerTrackingProgress(double progress)
{
    TrackerParamsProviderPtr provider = _imp->provider.lock();
    if (!provider) {
        return;
    }
    NodePtr node = provider->getTrackerNode();
    if (!node) {
        return;
    }
    if ( node->getApp() && !node->getApp()->progressUpdate(node, progress) ) {
        _imp->scheduler->abortThreadedTask();
    }
}
Esempio n. 3
0
void
TrackMarker::resetCenter()
{
    TrackerContextPtr context = getContext();

    assert(context);
    NodePtr input = context->getNode()->getInput(0);
    if (input) {
        SequenceTime time = input->getApp()->getTimeLine()->currentFrame();
        RenderScale scale;
        scale.x = scale.y = 1;
        RectD rod;
        bool isProjectFormat;
        StatusEnum stat = input->getEffectInstance()->getRegionOfDefinition_public(input->getHashValue(), time, scale, ViewIdx(0), &rod, &isProjectFormat);
        Point center;
        center.x = 0;
        center.y = 0;
        if (stat == eStatusOK) {
            center.x = (rod.x1 + rod.x2) / 2.;
            center.y = (rod.y1 + rod.y2) / 2.;
        }

        KnobDoublePtr centerKnob = getCenterKnob();
        centerKnob->setValue(center.x, ViewSpec::current(), 0);
        centerKnob->setValue(center.y, ViewSpec::current(), 1);
    }
}
Esempio n. 4
0
OneViewNode::OneViewNode(const NodePtr& n)
    : EffectInstance(n)
    , _imp( new OneViewNodePrivate() )
{
    setSupportsRenderScaleMaybe(eSupportsYes);
    if (n) {
        ProjectPtr project = n->getApp()->getProject();
        QObject::connect( project.get(), SIGNAL(projectViewsChanged()), this, SLOT(onProjectViewsChanged()) );
    }
}
void
TrackerNode::onTransformSolverWatcherProgress(int progress)
{
    assert(_imp->lastSolveRequest.tWatcher);
    NodePtr thisNode = getNode();
    double min = _imp->lastSolveRequest.tWatcher->progressMinimum();
    double max = _imp->lastSolveRequest.tWatcher->progressMaximum();
    double p = (progress - min) / (max - min);
    thisNode->getApp()->progressUpdate(thisNode, p);
}
Esempio n. 6
0
///High level test: render 1 frame of dot generator
TEST_F(BaseTest, GenerateDot)
{
    ///create the generator
    NodePtr generator = createNode(_generatorPluginID);

    ///create the writer and set its output filename
    NodePtr writer = createNode(_writeOIIOPluginID);

    ASSERT_TRUE(generator && writer);

    KnobIPtr frameRange = generator->getApp()->getProject()->getKnobByName("frameRange");
    ASSERT_TRUE(frameRange);
    KnobIntPtr knob = toKnobInt(frameRange);
    ASSERT_TRUE(knob);
    knob->setValue(1, ViewSpec::all(), 0);
    knob->setValue(1, ViewSpec::all(), 1);

    Format f(0, 0, 200, 200, "toto", 1.);
    generator->getApp()->getProject()->setOrAddProjectFormat(f);

    const QString& binPath = appPTR->getApplicationBinaryPath();
    QString filePath = binPath + QString::fromUtf8("/test_dot_generator.jpg");
    writer->setOutputFilesForWriter( filePath.toStdString() );

    ///attempt to connect the 2 nodes together
    connectNodes(generator, writer, 0, true);

    ///and start rendering. This call is blocking.
    std::list<AppInstance::RenderWork> works;
    AppInstance::RenderWork w;
    w.writer = toOutputEffectInstance( writer->getEffectInstance() );
    assert(w.writer);
    w.firstFrame = INT_MIN;
    w.lastFrame = INT_MAX;
    w.frameStep = INT_MIN;
    w.useRenderStats = false;
    works.push_back(w);
    getApp()->startWritersRendering(false, works);

    EXPECT_TRUE( QFile::exists(filePath) );
    QFile::remove(filePath);
}
void
TrackerNodePrivate::endSolve()
{
    lastSolveRequest.cpWatcher.reset();
    lastSolveRequest.tWatcher.reset();
    lastSolveRequest.keyframes.clear();
    lastSolveRequest.allMarkers.clear();
    setSolverParamsEnabled(true);
    NodePtr n = publicInterface->getNode();
    n->getApp()->progressEnd(n);
    n->getEffectInstance()->endChanges();
}
Esempio n. 8
0
void
TrackerHelper::onSchedulerTrackingStarted(int frameStep)
{
    TrackerParamsProviderPtr provider = _imp->provider.lock();
    if (!provider) {
        return;
    }
    NodePtr node = provider->getTrackerNode();
    if (!node) {
        return;
    }
    node->getApp()->progressStart(node, tr("Tracking...").toStdString(), "");
    Q_EMIT trackingStarted(frameStep);
}
Esempio n. 9
0
void
TrackerHelper::onSchedulerTrackingFinished()
{
    TrackerParamsProviderPtr provider = _imp->provider.lock();
    if (!provider) {
        return;
    }
    NodePtr node = provider->getTrackerNode();
    if (!node) {
        return;
    }
    node->getApp()->progressEnd( node );
    Q_EMIT trackingFinished();
}
void
TrackerNodePrivate::computeTransformParamsFromTracks()
{
    boost::shared_ptr<TrackerParamsProvider> thisShared = shared_from_this();

#ifndef TRACKER_GENERATE_DATA_SEQUENTIALLY
    lastSolveRequest.cpWatcher.reset();
    lastSolveRequest.tWatcher.reset( new QFutureWatcher<TransformData>() );
    QObject::connect( lastSolveRequest.tWatcher.get(), SIGNAL(finished()), publicInterface, SLOT(onTransformSolverWatcherFinished()) );
    QObject::connect( lastSolveRequest.tWatcher.get(), SIGNAL(progressValueChanged(int)), publicInterface, SLOT(onTransformSolverWatcherProgress(int)) );

    lastSolveRequest.tWatcher->setFuture( QtConcurrent::mapped( lastSolveRequest.keyframes, boost::bind(&TrackerHelper::computeTransformParamsFromTracksAtTime,
                                                                                                        lastSolveRequest.refTime,
                                                                                                        _1,
                                                                                                        lastSolveRequest.jitterPeriod,
                                                                                                        lastSolveRequest.jitterAdd,
                                                                                                        lastSolveRequest.robustModel,
                                                                                                        thisShared,
                                                                                                        center.lock(),
                                                                                                        lastSolveRequest.allMarkers)) );
#else
    NodePtr thisNode = publicInterface->getNode();
    QList<TransformData> validResults;
    {
        int nKeys = lastSolveRequest.keyframes.size();
        int keyIndex = 0;
        for (std::set<double>::const_iterator it = lastSolveRequest.keyframes.begin(); it != lastSolveRequest.keyframes.end(); ++it, ++keyIndex) {
            TransformData data = tracker->computeTransformParamsFromTracksAtTime(lastSolveRequest.refTime, *it, lastSolveRequest.jitterPeriod, lastSolveRequest.jitterAdd, lastSolveRequest.robustModel, thisShared, center.lock(), lastSolveRequest.allMarkers);
            if (data.valid) {
                validResults.push_back(data);
            }
            double progress = (keyIndex + 1) / (double)nKeys;
            thisNode->getApp()->progressUpdate(thisNode, progress);
        }
    }
    computeTransformParamsFromTracksEnd(lastSolveRequest.refTime, lastSolveRequest.maxFittingError, validResults);
#endif
} // TrackerContextPrivate::computeTransformParamsFromTracks
Esempio n. 11
0
void
TrackMarker::resetCenter()
{
    KnobItemsTablePtr model = getModel();
    if (!model) {
        return;
    }
    RectD rod;
    NodePtr input = model->getNode()->getInput(0);
    if (!input) {
        Format f;
        getApp()->getProject()->getProjectDefaultFormat(&f);
        rod = f.toCanonicalFormat();
    } else {
        TimeValue time(input->getApp()->getTimeLine()->currentFrame());
        RenderScale scale(1.);
        RectD rod;
        {
            GetRegionOfDefinitionResultsPtr results;
            ActionRetCodeEnum stat = input->getEffectInstance()->getRegionOfDefinition_public(time, scale, ViewIdx(0), &results);
            if (!isFailureRetCode(stat)) {
                rod = results->getRoD();
            }
        }
        Point center;
        center.x = 0;
        center.y = 0;
        center.x = (rod.x1 + rod.x2) / 2.;
        center.y = (rod.y1 + rod.y2) / 2.;


        KnobDoublePtr centerKnob = getCenterKnob();
        centerKnob->setValue(center.x, ViewSetSpec::all(), DimIdx(0));
        centerKnob->setValue(center.y, ViewSetSpec::all(), DimIdx(1));
    }
}
Esempio n. 12
0
std::pair<ImagePtr, RectI>
TrackMarker::getMarkerImage(int time,
                            const RectI& roi) const
{
    std::list<ImageComponents> components;

    components.push_back( ImageComponents::getRGBComponents() );

    const unsigned int mipmapLevel = 0;
    assert( !roi.isNull() );

    NodePtr node = getContext()->getNode();
    NodePtr input = node->getInput(0);
    if (!input) {
        return std::make_pair(ImagePtr(), roi);
    }

    AbortableRenderInfoPtr abortInfo = AbortableRenderInfo::create(false, 0);
    const bool isRenderUserInteraction = true;
    const bool isSequentialRender = false;
    AbortableThread* isAbortable = dynamic_cast<AbortableThread*>( QThread::currentThread() );
    if (isAbortable) {
        isAbortable->setAbortInfo( isRenderUserInteraction, abortInfo, node->getEffectInstance() );
    }

    ParallelRenderArgsSetter::CtorArgsPtr tlsArgs(new ParallelRenderArgsSetter::CtorArgs);
    tlsArgs->time = time;
    tlsArgs->view = ViewIdx(0);
    tlsArgs->isRenderUserInteraction = isRenderUserInteraction;
    tlsArgs->isSequential = isSequentialRender;
    tlsArgs->abortInfo = abortInfo;
    tlsArgs->treeRoot = getContext()->getNode();
    tlsArgs->textureIndex = 0;
    tlsArgs->timeline = node->getApp()->getTimeLine();
    tlsArgs->activeRotoPaintNode = NodePtr();
    tlsArgs->activeRotoDrawableItem = RotoDrawableItemPtr();
    tlsArgs->isDoingRotoNeatRender = false;
    tlsArgs->isAnalysis = true;
    tlsArgs->draftMode = true;
    tlsArgs->stats = RenderStatsPtr();
    ParallelRenderArgsSetter frameRenderArgs(tlsArgs);
    RenderScale scale;
    scale.x = scale.y = 1.;
    EffectInstance::RenderRoIArgs args( time,
                                        scale,
                                        mipmapLevel, //mipmaplevel
                                        ViewIdx(0),
                                        false,
                                        roi,
                                        RectD(),
                                        components,
                                        eImageBitDepthFloat,
                                        false,
                                        node->getEffectInstance(),
                                        eStorageModeRAM /*returnOpenGlTex*/,
                                        time);
    std::map<ImageComponents, ImagePtr> planes;
    EffectInstance::RenderRoIRetCode stat = input->getEffectInstance()->renderRoI(args, &planes);

    appPTR->getAppTLS()->cleanupTLSForThread();

    if ( (stat != EffectInstance::eRenderRoIRetCodeOk) || planes.empty() ) {
        return std::make_pair(ImagePtr(), roi);
    }

    return std::make_pair(planes.begin()->second, roi);
} // TrackMarker::getMarkerImage
Esempio n. 13
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
Esempio n. 14
0
/*
 * @brief This is called by LibMV to retrieve an image either for reference or as search frame.
 */
mv::FrameAccessor::Key
TrackerFrameAccessor::GetImage(int /*clip*/,
                               int frame,
                               mv::FrameAccessor::InputMode input_mode,
                               int downscale,            // Downscale by 2^downscale.
                               const mv::Region* region,     // Get full image if NULL.
                               const mv::FrameAccessor::Transform* /*transform*/, // May be NULL.
                               mv::FloatImage** destination)
{
    // Since libmv only uses MONO images for now we have only optimized for this case, remove and handle properly
    // other case(s) when they get integrated into libmv.
    assert(input_mode == mv::FrameAccessor::MONO);


    FrameAccessorCacheKey key;
    key.frame = frame;
    key.mipMapLevel = downscale;
    key.mode = input_mode;

    /*
       Check if a frame exists in the cache with matching key and bounds enclosing the given region
     */
    RectI roi;
    if (region) {
        convertLibMVRegionToRectI(*region, _imp->formatHeight, &roi);

        QMutexLocker k(&_imp->cacheMutex);
        std::pair<FrameAccessorCache::iterator, FrameAccessorCache::iterator> range = _imp->cache.equal_range(key);
        for (FrameAccessorCache::iterator it = range.first; it != range.second; ++it) {
            if ( (roi.x1 >= it->second.bounds.x1) && (roi.x2 <= it->second.bounds.x2) &&
                 ( roi.y1 >= it->second.bounds.y1) && ( roi.y2 <= it->second.bounds.y2) ) {
#ifdef TRACE_LIB_MV
                qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "Found cached image at frame" << frame << "with RoI x1="
                         << region->min(0) << "y1=" << region->max(1) << "x2=" << region->max(0) << "y2=" << region->min(1);
#endif
                // LibMV is kinda dumb on this we must necessarily copy the data either via CopyFrom or the
                // assignment constructor:
                // EDIT: fixed libmv
                *destination = it->second.image.get();
                //destination->CopyFrom<float>(*it->second.image);
                ++it->second.referenceCount;

                return (mv::FrameAccessor::Key)it->second.image.get();
            }
        }
    }

    EffectInstancePtr effect;
    if (_imp->trackerInput) {
        effect = _imp->trackerInput->getEffectInstance();
    }
    if (!effect) {
        return (mv::FrameAccessor::Key)0;
    }

    // Not in accessor cache, call renderRoI
    RenderScale scale;
    scale.y = scale.x = Image::getScaleFromMipMapLevel( (unsigned int)downscale );


    RectD precomputedRoD;
    if (!region) {
        bool isProjectFormat;
        StatusEnum stat = effect->getRegionOfDefinition_public(_imp->trackerInput->getHashValue(), frame, scale, ViewIdx(0), &precomputedRoD, &isProjectFormat);
        if (stat == eStatusFailed) {
            return (mv::FrameAccessor::Key)0;
        }
        double par = effect->getAspectRatio(-1);
        precomputedRoD.toPixelEnclosing( (unsigned int)downscale, par, &roi );
    }

    std::list<ImageComponents> components;
    components.push_back( ImageComponents::getRGBComponents() );

    NodePtr node = _imp->context->getNode();
    const bool isRenderUserInteraction = true;
    const bool isSequentialRender = false;
    AbortableRenderInfoPtr abortInfo = AbortableRenderInfo::create(false, 0);
    AbortableThread* isAbortable = dynamic_cast<AbortableThread*>( QThread::currentThread() );
    if (isAbortable) {
        isAbortable->setAbortInfo( isRenderUserInteraction, abortInfo, node->getEffectInstance() );
    }


    ParallelRenderArgsSetter::CtorArgsPtr tlsArgs(new ParallelRenderArgsSetter::CtorArgs);
    tlsArgs->time = frame;
    tlsArgs->view = ViewIdx(0);
    tlsArgs->isRenderUserInteraction = isRenderUserInteraction;
    tlsArgs->isSequential = isSequentialRender;
    tlsArgs->abortInfo = abortInfo;
    tlsArgs->treeRoot = node;
    tlsArgs->textureIndex = 0;
    tlsArgs->timeline = node->getApp()->getTimeLine();
    tlsArgs->activeRotoPaintNode = NodePtr();
    tlsArgs->activeRotoDrawableItem = RotoDrawableItemPtr();
    tlsArgs->isDoingRotoNeatRender = false;
    tlsArgs->isAnalysis = true;
    tlsArgs->draftMode = false;
    tlsArgs->stats = RenderStatsPtr();
    ParallelRenderArgsSetter frameRenderArgs(tlsArgs); // Stats
    EffectInstance::RenderRoIArgs args( frame,
                                        scale,
                                        downscale,
                                        ViewIdx(0),
                                        false,
                                        roi,
                                        precomputedRoD,
                                        components,
                                        eImageBitDepthFloat,
                                        true,
                                        _imp->context->getNode()->getEffectInstance(),
                                        eStorageModeRAM /*returnOpenGLTex*/,
                                        frame);
    std::map<ImageComponents, ImagePtr> planes;
    EffectInstance::RenderRoIRetCode stat = effect->renderRoI(args, &planes);
    if ( (stat != EffectInstance::eRenderRoIRetCodeOk) || planes.empty() ) {
#ifdef TRACE_LIB_MV
        qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "Failed to call renderRoI on input at frame" << frame << "with RoI x1="
                 << roi.x1 << "y1=" << roi.y1 << "x2=" << roi.x2 << "y2=" << roi.y2;
#endif

        return (mv::FrameAccessor::Key)0;
    }

    assert( !planes.empty() );
    const ImagePtr& sourceImage = planes.begin()->second;
    RectI sourceBounds = sourceImage->getBounds();
    RectI intersectedRoI;
    if ( !roi.intersect(sourceBounds, &intersectedRoI) ) {
#ifdef TRACE_LIB_MV
        qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "RoI does not intersect the source image bounds (RoI x1="
                 << roi.x1 << "y1=" << roi.y1 << "x2=" << roi.x2 << "y2=" << roi.y2 << ")";
#endif

        return (mv::FrameAccessor::Key)0;
    }

#ifdef TRACE_LIB_MV
    qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "renderRoi (frame" << frame << ") OK  (BOUNDS= x1="
             << sourceBounds.x1 << "y1=" << sourceBounds.y1 << "x2=" << sourceBounds.x2 << "y2=" << sourceBounds.y2 << ") (ROI = " << roi.x1 << "y1=" << roi.y1 << "x2=" << roi.x2 << "y2=" << roi.y2 << ")";
#endif

    /*
       Copy the Natron image to the LivMV float image
     */
    FrameAccessorCacheEntry entry;
    entry.image.reset( new MvFloatImage( intersectedRoI.height(), intersectedRoI.width() ) );
    entry.bounds = intersectedRoI;
    entry.referenceCount = 1;
    natronImageToLibMvFloatImage(_imp->enabledChannels,
                                 sourceImage.get(),
                                 intersectedRoI,
                                 *entry.image);
    // we ignore the transform parameter and do it in natronImageToLibMvFloatImage instead

    *destination = entry.image.get();
    //destination->CopyFrom<float>(*entry.image);

    //insert into the cache
    {
        QMutexLocker k(&_imp->cacheMutex);
        _imp->cache.insert( std::make_pair(key, entry) );
    }
#ifdef TRACE_LIB_MV
    qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "Rendered frame" << frame << "with RoI x1="
             << intersectedRoI.x1 << "y1=" << intersectedRoI.y1 << "x2=" << intersectedRoI.x2 << "y2=" << intersectedRoI.y2;
#endif

    return (mv::FrameAccessor::Key)entry.image.get();
} // TrackerFrameAccessor::GetImage
void
TrackerNodePrivate::exportTrackDataFromExportOptions()
{
    //bool transformLink = _imp->exportLink.lock()->getValue();
    KnobChoicePtr transformTypeKnob = transformType.lock();

    assert(transformTypeKnob);
    int transformType_i = transformTypeKnob->getValue();
    TrackerTransformNodeEnum transformType = (TrackerTransformNodeEnum)transformType_i;
    KnobChoicePtr motionTypeKnob = motionType.lock();
    if (!motionTypeKnob) {
        return;
    }
    int motionType_i = motionTypeKnob->getValue();
    TrackerMotionTypeEnum mt = (TrackerMotionTypeEnum)motionType_i;

    if (mt == eTrackerMotionTypeNone) {
        Dialogs::errorDialog( tr("Tracker Export").toStdString(), tr("Please select the export mode with the Motion Type parameter").toStdString() );

        return;
    }

    bool linked = exportLink.lock()->getValue();
    QString pluginID;
    switch (transformType) {
        case eTrackerTransformNodeCornerPin:
            pluginID = QString::fromUtf8(PLUGINID_OFX_CORNERPIN);
            break;
        case eTrackerTransformNodeTransform:
            pluginID = QString::fromUtf8(PLUGINID_OFX_TRANSFORM);
            break;
    }

    NodePtr thisNode = publicInterface->getNode();
    AppInstancePtr app = thisNode->getApp();
    CreateNodeArgsPtr args(CreateNodeArgs::create( pluginID.toStdString(), thisNode->getGroup() ));
    args->setProperty<bool>(kCreateNodeArgsPropAutoConnect, false);
    args->setProperty<bool>(kCreateNodeArgsPropSettingsOpened, false);

    NodePtr createdNode = app->createNode(args);
    if (!createdNode) {
        return;
    }

    // Move the new node
    double thisNodePos[2];
    double thisNodeSize[2];
    thisNode->getPosition(&thisNodePos[0], &thisNodePos[1]);
    thisNode->getSize(&thisNodeSize[0], &thisNodeSize[1]);
    createdNode->setPosition(thisNodePos[0] + thisNodeSize[0] * 2., thisNodePos[1]);

    TimeValue timeForFromPoints(referenceFrame.lock()->getValue());


    switch (transformType) {
        case eTrackerTransformNodeCornerPin: {
            KnobDoublePtr cornerPinToPoints[4];
            KnobDoublePtr cornerPinFromPoints[4];


            for (unsigned int i = 0; i < 4; ++i) {
                cornerPinFromPoints[i] = getCornerPinPoint(createdNode, true, i);
                assert(cornerPinFromPoints[i]);
                for (int j = 0; j < cornerPinFromPoints[i]->getNDimensions(); ++j) {
                    cornerPinFromPoints[i]->setValue(fromPoints[i].lock()->getValueAtTime(timeForFromPoints, DimIdx(j)), ViewSetSpec::all(), DimIdx(j));
                }

                cornerPinToPoints[i] = getCornerPinPoint(createdNode, false, i);
                assert(cornerPinToPoints[i]);
                if (!linked) {
                    cornerPinToPoints[i]->copyKnob( toPoints[i].lock() );
                } else {
                    bool ok = cornerPinToPoints[i]->linkTo(toPoints[i].lock());
                    (void)ok;
                    assert(ok);
                }
            }
            {
                KnobIPtr knob = createdNode->getKnobByName(kCornerPinParamMatrix);
                if (knob) {
                    KnobDoublePtr isType = toKnobDouble(knob);
                    if (isType) {
                        isType->copyKnob(cornerPinMatrix.lock() );
                    }
                }
            }
            break;
        }
        case eTrackerTransformNodeTransform: {
            KnobIPtr translateKnob = createdNode->getKnobByName(kTransformParamTranslate);
            if (translateKnob) {
                KnobDoublePtr isDbl = toKnobDouble(translateKnob);
                if (isDbl) {
                    if (!linked) {
                        isDbl->copyKnob(translate.lock() );
                    } else {
                        ignore_result(isDbl->linkTo(translate.lock()));
                    }
                }
            }

            KnobIPtr scaleKnob = createdNode->getKnobByName(kTransformParamScale);
            if (scaleKnob) {
                KnobDoublePtr isDbl = toKnobDouble(scaleKnob);
                if (isDbl) {
                    if (!linked) {
                        isDbl->copyKnob(scale.lock() );
                    } else {
                        ignore_result(isDbl->linkTo(scale.lock()));
                    }
                }
            }

            KnobIPtr rotateKnob = createdNode->getKnobByName(kTransformParamRotate);
            if (rotateKnob) {
                KnobDoublePtr isDbl = toKnobDouble(rotateKnob);
                if (isDbl) {
                    if (!linked) {
                        isDbl->copyKnob(rotate.lock());
                    } else {
                        ignore_result(isDbl->linkTo(rotate.lock()));
                    }
                }
            }
            KnobIPtr centerKnob = createdNode->getKnobByName(kTransformParamCenter);
            if (centerKnob) {
                KnobDoublePtr isDbl = toKnobDouble(centerKnob);
                if (isDbl) {
                    isDbl->copyKnob( center.lock() );
                }
            }
            break;
        }
    } // switch

    KnobIPtr cpInvertKnob = createdNode->getKnobByName(kTransformParamInvert);
    if (cpInvertKnob) {
        KnobBoolPtr isBool = toKnobBool(cpInvertKnob);
        if (isBool) {
            if (!linked) {
                isBool->copyKnob(invertTransform.lock());
            } else {
                ignore_result(isBool->linkTo(invertTransform.lock()));
            }
        }
    }

    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamMotionBlur);
        if (knob) {
            KnobDoublePtr isType = toKnobDouble(knob);
            if (isType) {
                isType->copyKnob(motionBlur.lock());
            }
        }
    }
    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamShutter);
        if (knob) {
            KnobDoublePtr isType = toKnobDouble(knob);
            if (isType) {
                isType->copyKnob(shutter.lock());
            }
        }
    }
    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamShutterOffset);
        if (knob) {
            KnobChoicePtr isType = toKnobChoice(knob);
            if (isType) {
                isType->copyKnob(shutterOffset.lock());
            }
        }
    }
    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamCustomShutterOffset);
        if (knob) {
            KnobDoublePtr isType = toKnobDouble(knob);
            if (isType) {
                isType->copyKnob(customShutterOffset.lock());
            }
        }
    }
} // exportTrackDataFromExportOptions
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
Esempio n. 17
0
void
moveGroupNode(DopeSheetEditor* model,
              const NodePtr& node,
              double dt)
{
    NodeGroupPtr group = node->isEffectNodeGroup();

    assert(group);
    NodesList nodes;
    group->getNodes_recursive(nodes, true);

    for (NodesList::iterator it = nodes.begin(); it != nodes.end(); ++it) {
        NodeGuiPtr nodeGui = boost::dynamic_pointer_cast<NodeGui>( (*it)->getNodeGui() );
        assert(nodeGui);
        std::string pluginID = (*it)->getPluginID();
        NodeGroupPtr isChildGroup = (*it)->isEffectNodeGroup();

        // Move readers
#ifndef NATRON_ENABLE_IO_META_NODES
        if ( ReadNode::isBundledReader( pluginID, node->getApp()->wasProjectCreatedWithLowerCaseIDs() ) ) {
#else
        if (pluginID == PLUGINID_NATRON_READ) {
#endif
            moveReader(*it, dt);
        } else if (pluginID == PLUGINID_OFX_TIMEOFFSET) {
            moveTimeOffset(*it, dt);
        } else if (pluginID == PLUGINID_OFX_FRAMERANGE) {
            moveFrameRange(*it, dt);
        } else if (isChildGroup) {
            moveGroupNode(model, *it, dt);
        }

        // Move keyframes
        const KnobsVec &knobs = (*it)->getKnobs();

        for (KnobsVec::const_iterator knobIt = knobs.begin(); knobIt != knobs.end(); ++knobIt) {
            const KnobIPtr& knob = *knobIt;
            if ( !knob->hasAnimation() ) {
                continue;
            }

            for (int dim = 0; dim < knob->getDimension(); ++dim) {
                if ( !knob->isAnimated( dim, ViewIdx(0) ) ) {
                    continue;
                }
                KeyFrameSet keyframes = knob->getCurve(ViewIdx(0), dim)->getKeyFrames_mt_safe();

                for (KeyFrameSet::iterator kfIt = keyframes.begin(); kfIt != keyframes.end(); ++kfIt) {
                    KeyFrame kf = (*kfIt);
                    KeyFrame fake;

                    knob->moveValueAtTime(eCurveChangeReasonDopeSheet, kf.getTime(), ViewSpec::all(), dim, dt, 0, &fake);
                }
            }
        }
    }
} // moveGroupNode

NATRON_NAMESPACE_ANONYMOUS_EXIT


////////////////////////// DSMoveKeysCommand //////////////////////////

DSMoveKeysAndNodesCommand::DSMoveKeysAndNodesCommand(const DSKeyPtrList &keys,
                                                     const std::vector<DSNodePtr >& nodes,
                                                     double dt,
                                                     DopeSheetEditor *model,
                                                     QUndoCommand *parent)
    : QUndoCommand(parent),
    _keys(keys),
    _nodes(),
    _dt(dt),
    _model(model)
{
    setText( tr("Move selected keys") );
    std::set<NodePtr > nodesSet;
    for (std::vector<DSNodePtr >::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
        DopeSheetItemType type = (*it)->getItemType();
        if ( (type != eDopeSheetItemTypeReader) &&
             ( type != eDopeSheetItemTypeGroup) &&
             ( type != eDopeSheetItemTypeTimeOffset) &&
             ( type != eDopeSheetItemTypeFrameRange) ) {
            //Note that Retime nodes cannot be moved
            continue;
        }
        _nodes.push_back(*it);
        nodesSet.insert( (*it)->getInternalNode() );
        NodeGroupPtr isGroup = (*it)->getInternalNode()->isEffectNodeGroup();
        if (isGroup) {
            NodesList recurseNodes;
            isGroup->getNodes_recursive(recurseNodes, true);
            for (NodesList::iterator it = recurseNodes.begin(); it != recurseNodes.end(); ++it) {
                nodesSet.insert(*it);
            }
        }
    }

    for (DSKeyPtrList::iterator it = _keys.begin(); it != _keys.end(); ++it) {
        KnobHolderPtr holder = (*it)->getContext()->getInternalKnob()->getHolder();
        assert(holder);
        EffectInstancePtr isEffect = toEffectInstance(holder);
        if (isEffect) {
            nodesSet.insert( isEffect->getNode() );
        }
    }

    for (std::set<NodePtr >::iterator it = nodesSet.begin(); it != nodesSet.end(); ++it) {
        _allDifferentNodes.push_back(*it);
    }
}

void
DSMoveKeysAndNodesCommand::undo()
{
    moveSelection(-_dt);
}