Решение на основе указателей
Преобразует xt::xarray <-> cv::mat(1f)
на основе указателей на базовые данные исходного объекта. Копирование данных не требуется, но может потребоваться освобождение памяти.
Указатель на данные пользователя. Конструкторы матриц, которые принимают данные и параметры шага, не выделяют матричные данные. Вместо этого они просто инициализируют заголовок матрицы, который указывает на указанные данные, что означает, что данные не копируются. Эта операция очень эффективна и может использоваться для обработки внешних данных с помощью функций OpenCV. Внешние данные не удаляются автоматически, поэтому вам следует позаботиться об этом.
Сравните документацию .
Не используйте вызов по значению , при преобразовании: Если конвертировать преобразователь в функцию (сравните xarray_to_mat
), будьте осторожны, чтобы использовать вызов по ссылке. В противном случае указатель xarr.data()
указывает на невыделенную позицию памяти.
xt :: layout_type :: column_major: Конечно, column_major layout
в 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]