【问题标题】:converting xtensor xarray to opencv mat back and forth in cpp在cpp中来回将xtensor xarray转换为opencv mat
【发布时间】:2020-10-30 21:55:55
【问题描述】:

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

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

逐元素解决方案

#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     }}

【问题讨论】:

    标签: c++ opencv python-xarray opencv-mat xtensor


    【解决方案1】:

    基于指针的解决方案

    这会根据指向源对象基础数据的指针转换xt::xarray &lt;-&gt; cv::mat(1f)。不需要复制数据,但可能需要释放内存。

    指向用户数据的指针。获取数据和步骤的矩阵构造函数 参数不分配矩阵数据。相反,他们只是初始化 指向指定数据的矩阵头,这意味着 没有数据被复制。这个操作效率很高,可以用来 使用 OpenCV 函数处理外部数据。外部数据不 自动释放,所以你应该照顾它。

    比较documentation

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

    xt::layout_type::column_major: 当然,xtensor 中的column_major layout 会带来一些麻烦。 在这种情况下,回退到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]
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2011-09-12
        • 1970-01-01
        • 2018-09-04
        • 2015-12-13
        • 2017-02-19
        • 2018-11-28
        • 2015-02-16
        • 1970-01-01
        相关资源
        最近更新 更多