传递 opencv inputarray 并将其用作 std::vector

Posted

技术标签:

【中文标题】传递 opencv inputarray 并将其用作 std::vector【英文标题】:Pass opencv inputarray and use it as std::vector 【发布时间】:2014-09-09 16:51:03 【问题描述】:

我想编写一个使用 cv::InputArray 作为参数的自定义函数。 在函数中,我知道我可以使用 cv::InputArray::getMat 来获取输入 cv::Mat 的标题。

在将 std::vector 传递给 cv::InputArray 时我有些困惑。

1.如果我将 std::vector 传递给函数,我还能在函数中获取 std::vector 吗?例如:

void foo(cv::InputArray _input)

    std::vector<cv::Point2f> input = _input.getVector() // getVector function doesn't exist


std::vector<cv::Point2f> a;
foo(a);

2.如果我将 std::vector 传递给函数并使用 getMat 在函数中获取 cv::Mat,那么 mat 会是什么样子?

对于std::vector&lt;char&gt;的情况,保利做了明确的解释。如果我想在函数中得到std::vector&lt;cv::Point2f&gt;,有什么建议吗?

非常感谢。

【问题讨论】:

【参考方案1】:

当您将向量传递给采用InputArray 的函数时,您会隐式调用转换构造函数InputArray::InputArray(vector)。 (这里解释了转换构造函数:https://***.com/a/15077788/928387)

在这个构造函数中,向量的指针被简单地赋值给 InputArray 中的obj 成员变量。如果你使用 OpenCV 3.0,InputArray 有 getObj() 方法,所以你可以通过以下方式获取向量:

// Only works on OpenCV 3.0 or above
const std::vector<Point2f>& input = *(const std::vector<Point2f>*)_input.getObj();

如果你使用 OpenCV 2.X,你可以使用InputArray::getMat()。它返回具有指向数据的指针的Mat 对象。所以你也可以这样做。

// Should Work on any OpenCV version
cv::Mat mat = _input.getMat();
Point2f *data = (Point2f *)mat.data;
int length = mat.total();
std::vector<Point2f> input;
input.assign(data, data + length);

关于您的第二个问题,如果您在具有 N 个元素的 InputArray 对象上调用 InputArray::getMat(),它会返回 (N*1) 矩阵。

【讨论】:

您好,感谢您的回答。我尝试了两种方法,但都没有奏效。对于第一种方式,InputArray 没有 getObj() 方法,所以我假设您的意思是 getMat()。这给了我编译错误,例如:无法从 'cv::Mat' 转换为 'const std::vector<_ty> *'。对于第二种方法,我想恢复cv::Point2f的向量,但是结果不正确。 似乎只有 OpenCV 3.0 有 getObj() 方法。我更新了我的原始答案以包含版本描述并使用 Point2f。我使用 OpenCV 2.4.8 在我的机器上成功恢复了 vector。请检查一下。【参考方案2】:

请注意,InputArray::getObj() 返回创建它的对象。因此,如果 _input 是使用 std::vector 创建的,则投射 only 有效!这可以通过InputArray::isVector() 进行检查。

否则,必须创建一个新的std::vector 对象。不幸的是,没有办法告诉std::vector 使用现有数据。我认为使用您自己的allocator 时甚至不可能。如果您仍然想要std::vector,请使用指针/迭代器(在constructor 或std::vector::assign() 中)创建带有数据副本的新对象。您可以通过InputArray::total() 直接从_input 获取大小。

矢量

基于之前的观察,我结合Poly提出的尝试。

std::vector<Point2f> *input;
if (_input.isVector()) 
    input = static_cast<std::vector<Point2f>*>(_input.getObj());
 else 
    size_t length = _input.total();
    Point2f* data = reinterpret_cast<Point2f*>(_input.getMat().data);
    input = new std::vector<Point2f>(data, data + length);

模板

要重用其他类型的代码,我建议使用模板。

template<class T>
std::vector<T>& getVec(InputArray _input) 
    std::vector<T> *input;
    if (_input.isVector()) 
        input = static_cast<std::vector<T>*>(_input.getObj());
     else 
        size_t length = _input.total();
        T* data = reinterpret_cast<T*>(_input.getMat().data);
        input = new std::vector<T>(data, data + length);
    
    return *input;

此外,您应该通过InputArray::type() 检查类型是否兼容。

数组

如果您只想轻松索引,当然可以使用标准 C 样式的数组(注意 C++ 样式的 std::array 也需要复制数据)。

Point2f* data = reinterpret_cast<Point2f*>(_input.getMat().data);

然后您可以通过

访问数据
Point2f p = data[5];

【讨论】:

以上是关于传递 opencv inputarray 并将其用作 std::vector的主要内容,如果未能解决你的问题,请参考以下文章

为啥 OPENCV 中有这么多函数使用 InputArray 和 OutputArray 作为函数参数?

将 Qt QByteArray 转换为 OpenCV cv::InputArray

OpenCV InputArray和OutputArray

OpenCV InputArray和OutputArray

OpenCv 第一步 - 不存在合适的构造函数来将“IplImage *”转换为“cv::_InputArray”

opencv solvepnp函数各种方法比较