c++ - 如何使 OpenCV 跟踪类从基类派生?

标签 c++ opencv

OpenCV 跟踪 API 在 3 个不同的地方实现。

  • video/tracking.hpp
  • tracking.hpp
  • tracking/tracking_legacy.hpp

我希望能够通过提供算法名称作为输入来使用任何实现。

cv::Ptr<cv::Tracker> get_tracker(std::string trackerType);

A similar approach with Python似乎有效。

if tracker_type == 'CSRT':
    tracker = cv2.TrackerCSRT_create()
elif tracker_type == 'MOSSE':
    tracker = cv.legacy.TrackerMOSSE_create()
...
ok = tracker.init(frame, bbox)
ok, bbox = tracker.update(frame)

C++ 的问题是 tracker 的类型应该在编译时已知。

different implementations using templates是函数的解决方案,但我们返回一个对象,所以这不适用。

正确的解决方案是使用继承来派生 cv::Trackercv::legacy::Tracker来自具有纯虚函数 initupdate 的基类。这两个类都有这些方法,但它们分别派生自 cv::Algorithm,后者不具有任何这些函数。

到目前为止,我创建了单独的函数来获取跟踪器对象。

#include <opencv2/tracking.hpp>
#include <opencv2/tracking/tracking_legacy.hpp>
#include <string>
#include <stdexcept>

// https://docs.opencv.org/4.5.2/d0/d0a/classcv_1_1Tracker.html
cv::Ptr<cv::Tracker> get_tracker(std::string trackerType)
{
    if (trackerType == "MIL")
        return cv::TrackerMIL::create();
    if (trackerType == "GOTURN")
        return cv::TrackerGOTURN::create();
    if (trackerType == "CSRT")
        return cv::TrackerCSRT::create();
    if (trackerType == "KCF")
        return cv::TrackerKCF::create();
    throw std::runtime_error("Unknown tracker type.");
}

// https://docs.opencv.org/4.5.2/db/dfe/classcv_1_1legacy_1_1Tracker.html
cv::Ptr<cv::legacy::Tracker> get_legacy_tracker(std::string legacyTrackerType)
{
    if (legacyTrackerType == "MIL")
        return cv::legacy::TrackerMIL::create();
    if (legacyTrackerType == "BOOSTING")
        return cv::legacy::TrackerBoosting::create();
    if (legacyTrackerType == "MEDIANFLOW")
        return cv::legacy::TrackerMedianFlow::create();
    if (legacyTrackerType == "TLD")
        return cv::legacy::TrackerTLD::create();
    if (legacyTrackerType == "KCF")
        return cv::legacy::TrackerKCF::create();
    if (legacyTrackerType == "MOSSE")
        return cv::legacy::TrackerMOSSE::create();
    if (legacyTrackerType == "CSRT")
        return cv::legacy::TrackerCSRT::create();
    throw std::runtime_error("Unknown legacy tracker type.");
}

我将跟踪器类型作为命令行输入。任何使以下代码适用于所有跟踪器类型的解决方案都值得赞赏。在可用时,Tracker 优先于legacy

tracker->init(frame, bbox);
bool ok = tracker->update(frame, bbox);

注意:我使用的是 OpenCV 4.5.2。 legacy 模块在this commit中创建.

另一个说明:目前,opencv-python==4.5.2的pip包不可用。提供的Python代码未经测试,而是根据文档编写的。

最佳答案

解决方案在于OpenCV的示例脚本中。 (tracking/samples/samples_utility.hpp)

我们需要将 cv::legacy::Tracker 转换为首选类型 cv::Tracker。就像函数的不同输入问题一样,我们需要分别实现这些成员函数。

class LegacyTrackerWrapper : public cv::Tracker
{
    const cv::Ptr<cv::legacy::Tracker> legacy_tracker_;

public:
    LegacyTrackerWrapper(const cv::Ptr<legacy::Tracker>& legacy_tracker)
        : legacy_tracker_(legacy_tracker) {}

    ~LegacyTrackerWrapper() override {}

    void init(cv::InputArray image, const cv::Rect& boundingBox) override
    {
        legacy_tracker_->init(image, static_cast<cv::Rect2d>(boundingBox));
    }

    bool update(cv::InputArray image, cv::Rect& boundingBox) override
    {
        cv::Rect2d boundingBox2d;
        bool res = legacy_tracker_->update(image, boundingBox2d);
        boundingBox = static_cast<cv::Rect>(boundingBox2d);  // the cast is not defined by default
        return res;
    }
};

我们可以使用包装类来获得所需的行为。

cv::Ptr<cv::Tracker> upgradeTrackingAPI(const cv::Ptr<legacy::Tracker>& legacy_tracker)
{
    return cv::makePtr<LegacyTrackerWrapper>(legacy_tracker);
}

cv::Ptr<cv::Tracker> get_tracker(std::string trackerType)
{
    if (trackerType == "CSRT")
        return cv::TrackerCSRT::create();
    if (trackerType == "MOSSE")
        return upgradeTrackingAPI(cv::legacy::TrackerMOSSE::create());
}

关于c++ - 如何使 OpenCV 跟踪类从基类派生?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67159945/

相关文章:

c++ - 什么使 C/C++ 程序成为 32/64 位?

c++ - 使用 OpenCV CascadeClassifier 的内存泄漏

python - 如何从目录中找到与输入图像相似的图像?

c++ - 私有(private)/公共(public) header 示例?

c++ - 在派生类之间复制共享变量(浅复制就足够了)

C++货币转换器尾随零

c++ - 如何将 vector 中的数据添加到cv::Mat?

opencv - OpenCV SURF比较描述符

java - 是什么导致 opencv_traincascade.exe 在获取负样本时崩溃?

c++ - 堆栈溢出错误是否会触发核心转储,如果触发是否有用?