1

我正在寻找一种快速可靠的转换方式xt::xarray <-> cv::mat / cv::mat1f。在我的具体情况下,我对 2 维和数据类型浮点数表示什么,但当然欢迎更一般的答案!

目前,我有一个元素解决方案。这是非常强大的,但我希望有一个更快的。我在实现这一点时遇到了一些麻烦。

Elementwise 解决方案

#include <iostream>

#include <opencv2/opencv.hpp>

#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
#include "xtensor/xadapt.hpp"


cv::Mat xarray_to_mat_elementwise(xt::xarray<float> xarr)
{
    int ndims = xarr.dimension();
    assert(ndims == 2  && "can only convert 2d xarrays");
    int nrows = xarr.shape()[0];
    int ncols = xarr.shape()[1];
    cv::Mat mat(nrows, ncols, CV_32FC1);
    for (int rr=0; rr<nrows; rr++)
    {
        for (int cc=0; cc<ncols; cc++)
        {
            mat.at<float>(rr, cc) = xarr(rr, cc);
        }
    }
    return mat;
}

xt::xarray<float> mat_to_xarray_elementwise(cv::Mat mat)
{
    int ndims = mat.dims;
    assert(ndims == 2  && "can only convert 2d xarrays");
    int nrows = mat.rows;
    int ncols = mat.cols;
    xt::xarray<float> xarr = xt::empty<float>({nrows, ncols});
    for (int rr=0; rr<nrows; rr++)
    {
        for (int cc=0; cc<ncols; cc++)
        {
            xarr(rr, cc) = mat.at<float>(rr, cc);
        }
    }
    return xarr;
}



int main()
{
    int nrows = 2, ncols = 3;
    float data[150];
    for (int i=0; i<nrows * ncols; i++)
    {
        data[i] = .1 * i;
    }

    cv::Mat mat (nrows, ncols, CV_32FC1, data, 0);
    std::cout << "mat:\n" << mat << std::endl;

    xt::xarray<float> xarr = xt::adapt(
        (float*) data, nrows * ncols, xt::no_ownership(), std::vector<std::size_t> {nrows, ncols});
    std::cout << "xarr:\n" << xarr << std::endl;

    cv::Mat mat2_ew = xarray_to_mat_elementwise(xarr);
    std::cout << "mat2_ew (from xt::xarray):\n" << mat2_ew << std::endl;

    xt::xarray<float> xarr2_ew = mat_to_xarray_elementwise(mat);
    std::cout << "xarr2_ew (from cv::mat):\n" << xarr2_ew << std::endl;

    return 0;
}

输出

mat:
[0, 0.1, 0.2;
 0.30000001, 0.40000001, 0.5]
xarr:
{{ 0.      ,  0.1     ,  0.2     },
 { 0.3     ,  0.4     ,  0.5     }}
mat2_ew (from xt::xarray):
[0, 0.1, 0.2;
 0.30000001, 0.40000001, 0.5]
xarr2_ew (from cv::mat):
{{ 0.      ,  0.1     ,  0.2     },
 { 0.3     ,  0.4     ,  0.5     }}
4

2 回答 2

1

基于指针的解决方案

xt::xarray <-> cv::mat(1f)基于指向源对象基础数据的指针进行转换。不需要复制数据,但可能需要释放内存。

指向用户数据的指针。采用数据和步骤参数的矩阵构造函数不分配矩阵数据。相反,它们只是初始化指向指定数据的矩阵头,这意味着没有数据被复制。此操作非常高效,可用于使用 OpenCV 函数处理外部数据。外部数据不会自动释放,因此您应该注意它。

比较文档

转换时不要使用按值调用: 如果将转换器包装在函数中(比较xarray_to_mat),请小心使用按引用调用。否则指针xarr.data()指向一个未分配的内存位置。

xt::layout_type::column_major: 当然,column_major layoutin xtensor 会带来一些麻烦。elementwise assignment在这种情况下,回退到 或许是有意义的。

#include <iostream>
#include <opencv2/opencv.hpp>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
#include "xtensor/xadapt.hpp"

/**
 * Converts xt::xarray to cv::mat.
 *
 * First few elements are wrong (not reproducible).
 * This can be repaired by using call by reference: xt::xarray<float> xarr -> xt::xarray<float> & xarr
 */
cv::Mat xarray_to_mat(xt::xarray<float> xarr)
{
    cv::Mat mat (xarr.shape()[0], xarr.shape()[1], CV_32FC1, xarr.data(), 0);
    return mat;
}

xt::xarray<float> mat_to_xarray(cv::Mat mat)
{
    xt::xarray<float> res = xt::adapt(
        (float*) mat.data, mat.cols * mat.rows, xt::no_ownership(), std::vector<std::size_t> {mat.rows, mat.cols});
    return res;
}

cv::Mat xarray_to_mat_elementwise(xt::xarray<float> xarr)
{
    int ndims = xarr.dimension();
    assert(ndims == 2  && "can only convert 2d xarrays");
    int nrows = xarr.shape()[0];
    int ncols = xarr.shape()[1];
    cv::Mat mat(nrows, ncols, CV_32FC1);
    for (int rr=0; rr<nrows; rr++)
    {
        for (int cc=0; cc<ncols; cc++)
        {
            mat.at<float>(rr, cc) = xarr(rr, cc);
        }
    }
    return mat;
}

xt::xarray<float> mat_to_xarray_elementwise(cv::Mat mat)
{
    int ndims = mat.dims;
    assert(ndims == 2  && "can only convert 2d xarrays");
    int nrows = mat.rows;
    int ncols = mat.cols;
    xt::xarray<float> xarr = xt::empty<float>({nrows, ncols});
    for (int rr=0; rr<nrows; rr++)
    {
        for (int cc=0; cc<ncols; cc++)
        {
            xarr(rr, cc) = mat.at<float>(rr, cc);
        }
    }
    return xarr;
}

int main()
{
    int nrows = 2, ncols = 3;
    float data[150];
    for (int i=0; i<nrows * ncols; i++)
    {
        data[i] = .1 * i;
    }

    cv::Mat mat (nrows, ncols, CV_32FC1, data, 0);
    std::cout << "mat:\n" << mat << std::endl;

    xt::xarray<float> xarr = xt::adapt(
        (float*) data, nrows * ncols, xt::no_ownership(), std::vector<std::size_t> {nrows, ncols});
    std::cout << "xarr:\n" << xarr << std::endl;

    cv::Mat mat2 (nrows, ncols, CV_32FC1, xarr.data(), 0);
    std::cout << "mat2 (from xt::xarray, works):\n" << mat2 << std::endl;

    cv::Mat mat3 = xarray_to_mat(xarr);
    std::cout << "mat3 (from xt::xarray, call by value -> fails):\n" << mat3 << std::endl;

    xt::xarray<float> xarr2 = mat_to_xarray(mat);
    std::cout << "xarr2 (from cv::mat):\n" << xarr2 << std::endl;

    std::cout << "\n=========== works for cv::mat1f analoguous ===========\n" << std::endl;

    cv::Mat1f mat_1f (nrows, ncols, data, 0);
    std::cout << "mat_1f:\n" << mat_1f << std::endl;

    cv::Mat1f mat_1f_2 (nrows, ncols, (float*) xarr.data(), 0);
    std::cout << "mat_1f_2 (from xt::xarray, works):\n" << mat_1f_2 << std::endl;

    std::cout << "\n=========== column_major layout in xtensor ===========\n" << std::endl;

    xt::xarray<float, xt::layout_type::column_major> xarr_cm = xt::adapt(
        (float*) data, nrows * ncols, xt::no_ownership(), std::vector<std::size_t> {nrows, ncols});
    std::cout << "xarr_cm:\n" << xarr_cm << std::endl;

    cv::Mat mat_cm (nrows, ncols, CV_32FC1, xarr_cm.data(), 0);
    std::cout << "mat_cm (from xt::xarray, pointer based -> fails):\n" << mat_cm << std::endl;

    cv::Mat mat_cm_ew = xarray_to_mat_elementwise(xarr_cm);
    std::cout << "mat_cm_ew (from xt::xarray, elementwise -> works):\n" << mat_cm_ew << std::endl;

    return 0;
}

** 输出 **

mat:
[0, 0.1, 0.2;
 0.30000001, 0.40000001, 0.5]
xarr:
{{ 0.      ,  0.1     ,  0.2     },
 { 0.3     ,  0.4     ,  0.5     }}
mat2 (from xt::xarray, works):
[0, 0.1, 0.2;
 0.30000001, 0.40000001, 0.5]
mat3 (from xt::xarray, call by value -> fails):
[4.3654774e-38, 0, 0.2;
 0.30000001, 0.40000001, 0.5]
xarr2 (from cv::mat):
{{ 0.      ,  0.1     ,  0.2     },
 { 0.3     ,  0.4     ,  0.5     }}

=========== works for cv::mat1f analoguous ===========

mat_1f:
[0, 0.1, 0.2;
 0.30000001, 0.40000001, 0.5]
mat_1f_2 (from xt::xarray, works):
[0, 0.1, 0.2;
 0.30000001, 0.40000001, 0.5]

=========== column_major layout in xtensor ===========

xarr_cm:
{{ 0.      ,  0.1     ,  0.2     },
 { 0.3     ,  0.4     ,  0.5     }}
mat_cm (from xt::xarray, pointer based -> fails):
[0, 0.30000001, 0.1;
 0.40000001, 0.2, 0.5]
mat_cm_ew (from xt::xarray, elementwise -> works):
[0, 0.1, 0.2;
 0.30000001, 0.40000001, 0.5]
于 2020-07-10T07:44:41.773 回答
0

如果传递给的 Matmat_to_xarray不是浮点数,那么演员表会很糟糕。将 Mat 转换为与演员表相同的数据类型可能会使事情更安全一些。mat.convertTo(mat, CV_32F);

于 2021-06-25T15:15:42.050 回答