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

Pass opencv inputarray and use it as std::vector

本文关键字:std vector opencv inputarray 传递      更新时间:2023-10-16

我想编写一个自定义函数,使用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<char>的情况做出了明确的解释。如果我想在函数中获得std::vector<cv::Point2f>,有什么建议吗?

非常感谢。

当您将vector传递给接受InputArray的函数时,您将隐式调用转换构造函数InputArray::InputArray(vector)。(转换构造函数的说明如下:https://stackoverflow.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()返回创建它的对象。因此,如果_input是使用std::vector创建的,则仅铸造有效!这可以通过InputArray::isVector()进行检查。

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

矢量

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

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];