OpenCV CommandLineParser未指定参数

OpenCV CommandLineParser Unspecified Params

本文关键字:参数 未指定 CommandLineParser OpenCV      更新时间:2023-10-16

使用cv::CommandLineParser时,是否可以解析任意长的非标志参数列表?
例如:

> app -a -b=2 a.txt b.txt c.txt ... 

我想访问所有非标志"位置"参数,而不必在keys规范中定义预定义的数量。此号码仅由应用程序的调用者决定。

OpenCV CommandLineParser不能处理数目可变的位置参数。您可以:

  1. 传递一个额外的参数(例如-N),指定位置参数的数量;
  2. 考虑所有不以-开头的参数都是位置参数。

然后,您可以使用与cv::CommandLineParser相同的接口创建一个自定义命令行解析器,该解析器能够处理可变数量的位置参数。

选项1

struct CustomCLP
{
    CustomCLP(int argc, const char* const argv[], const cv::String& keys, const String& positional_id)
    {
        String pos_key = "{" + positional_id + "|0|}";
        cv::CommandLineParser pos_clp(argc, argv, pos_key);
        _N = pos_clp.get<int>(positional_id);
        cv::String pos_keys = keys;
        for (int i=0; i<_N; ++i)
        {
            pos_keys += "{@pos" + to_string(i) + "||}";
        }
        _clp = new CommandLineParser(argc, argv, pos_keys);
    }
    ~CustomCLP()
    {
        delete _clp;
    }
    bool check() const {return _clp->check();}
    bool has(const cv::String& name) const {return _clp->has(name);}
    template<typename T>
    T get(const String& name, bool space_delete = true) const
    {
        return _clp->get<T>(name, space_delete);
    }
    template<typename T>
    T get(int index, bool space_delete = true) const
    {
        return _clp->get<T>(index, space_delete);
    }
    int n_positional_args() const { return _N;}
private:
    CommandLineParser* _clp;
    int _N;
};

你可以指定额外的参数(例如-N)来指定位置参数的数量。在构造函数中,解析这个数字,并为每个位置参数创建一个。然后你可以像往常一样使用它。

选项2

// SO: http://stackoverflow.com/a/17976541/5008845
inline std::string trim(const std::string &s)
{
    auto  wsfront = std::find_if_not(s.begin(), s.end(), std::isspace);
    return std::string(wsfront, std::find_if_not(s.rbegin(), std::string::const_reverse_iterator(wsfront), std::isspace).base());
}
struct CustomCLP2
{
    CommandLineParser _clp;
    vector<std::string> pos_args;
public:
    CustomCLP2(int argc, const char* const argv[], const cv::String& keys) :
        _clp(argc, argv, keys)
    {
        for (int i = 1; i < argc; ++i)
        {
            std::string s(argv[i]);
            s = trim(s);
            if (s[0] == '-') continue;
            pos_args.push_back(s);
        }
    }
    bool check() const { return _clp.check(); }
    bool has(const cv::String& name) const { return _clp.has(name); }
    template<typename T>
    T get(const String& name, bool space_delete = true) const
    {
        return _clp.get<T>(name, space_delete);
    }
    template<typename T>
    T get(int index, bool space_delete = true) const
    {
        stringstream ss;
        ss << pos_args[index];
        T t;
        ss >> t;
        return t;
    }
    template<>
    cv::String get(int index, bool space_delete) const
    {
        return cv::String(pos_args[index]);
    }
    int n_positional_args() const { return pos_args.size(); }
};

在构造函数中,保存所有不以-开头的参数。然后您可以像往常一样检索它。

使用

注意接口与CommandLineParser是一致的(在这个例子中,aboutgetPathToApplication等几个方法是不可用的,但是很容易将它们添加到自定义类中)。

命令行参数为:

Option 1: -a -b=2 -N=3 a.txt b.txt c.txt
Option 2: -a -b=2 a.txt b.txt c.txt
代码:

#include <opencv2opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

struct CustomCLP
{
    CustomCLP(int argc, const char* const argv[], const cv::String& keys, const String& positional_id)
    {
        String pos_key = "{" + positional_id + "|0|}";
        cv::CommandLineParser pos_clp(argc, argv, pos_key);
        _N = pos_clp.get<int>(positional_id);
        cv::String pos_keys = keys;
        for (int i=0; i<_N; ++i)
        {
            pos_keys += "{@pos" + to_string(i) + "||}";
        }
        _clp = new CommandLineParser(argc, argv, pos_keys);
    }
    ~CustomCLP()
    {
        delete _clp;
    }
    bool check() const {return _clp->check();}
    bool has(const cv::String& name) const {return _clp->has(name);}
    template<typename T>
    T get(const String& name, bool space_delete = true) const
    {
        return _clp->get<T>(name, space_delete);
    }
    template<typename T>
    T get(int index, bool space_delete = true) const
    {
        return _clp->get<T>(index, space_delete);
    }
    int n_positional_args() const { return _N;}
private:
    CommandLineParser* _clp;
    int _N;
};
// SO: http://stackoverflow.com/a/17976541/5008845
inline std::string trim(const std::string &s)
{
    auto  wsfront = std::find_if_not(s.begin(), s.end(), std::isspace);
    return std::string(wsfront, std::find_if_not(s.rbegin(), std::string::const_reverse_iterator(wsfront), std::isspace).base());
}
struct CustomCLP2
{
    CommandLineParser _clp;
    vector<std::string> pos_args;
public:
    CustomCLP2(int argc, const char* const argv[], const cv::String& keys) :
        _clp(argc, argv, keys)
    {
        for (int i = 1; i < argc; ++i)
        {
            std::string s(argv[i]);
            s = trim(s);
            if (s[0] == '-') continue;
            pos_args.push_back(s);
        }
    }
    bool check() const { return _clp.check(); }
    bool has(const cv::String& name) const { return _clp.has(name); }
    template<typename T>
    T get(const String& name, bool space_delete = true) const
    {
        return _clp.get<T>(name, space_delete);
    }
    template<typename T>
    T get(int index, bool space_delete = true) const
    {
        stringstream ss;
        ss << pos_args[index];
        T t;
        ss >> t;
        return t;
    }
    template<>
    cv::String get(int index, bool space_delete) const
    {
        return cv::String(pos_args[index]);
    }
    int n_positional_args() const { return pos_args.size(); }
};

int main(int argc, char* argv[])
{
    String keys =   
        "{a | | whatever a}"
        "{b | 1 | whatever b}";
    //CustomCLP clp(argc, argv, keys, "N");
    CustomCLP2 clp(argc, argv, keys);
    if (clp.has("a")) {
        cout << "Has <a>" << endl;
    }
    else {
        cout << "Doesn't have <a>";
    }
    int b = clp.get<int>("b");
    cout << "<b> : " << b << endl;
    int N = clp.n_positional_args();
    for (int i = 0; i < N; ++i)
    {
        cout << to_string(i) << ": " << clp.get<cv::String>(i) << endl;
    }
    return 0;
}