void ViewerDisplayScheduler::onRenderStopped(bool /*/aborted*/) { // Refresh all previews in the tree NodePtr effect = getOutputNode(); effect->getApp()->refreshAllPreviews(); if ( effect->getApp()->isGuiFrozen() ) { getEngine()->s_refreshAllKnobs(); } }
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(); } }
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); } }
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); }
///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(); }
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); }
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
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)); } }
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
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(¢erKeys); 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
/* * @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
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); }