xtensor 学习笔记
类似于 python 的 numpy 库的 c++ 实现 xtensor 学习记录。
1. stl-like 容器转为 xarray
#include <cstddef>
#include <vector>
#include <xtensor/xarray.hpp>
#include <xtensor/xadapt.hpp>
std::vector<double> v = {1., 2., 3., 4., 5., 6. };
std::vector<std::size_t> shape = { 2, 3 };
auto a1 = xt::adapt(v, shape);
// res = {{ 1., 2., 3. }, { 4., 5., 6. }};
参考: https://xtensor.readthedocs.io/en/latest/adaptor.html https://xtensor.readthedocs.io/en/latest/api/xtensor_adaptor.html?highlight=adapt
2. opencv mat 转为 xarray,其实 opencv 不用转也可以直接和 xarray 进行加减等操作。
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
#include "xtensor/xadapt.hpp"
Mat m = Mat::eye(4, 4, CV_8U);
cout << m << endl;
cout << "mat total size: " << m.total()
<< ", mat channels: " << m.channels()
<< ", mat cols: " << m.cols << ", mat rows: " << m.rows << endl;
cout << "-----" << endl;
//vector<int> shape = {m.rows, m.cols, m.channels()};
vector<int> shape = {m.rows, m.cols};
//vector<int> shape = {m.rows * m.colss};
xarray<uint8_t> res = adapt((uint8_t *)m.data, m.total() * m.channels(),
no_ownership(), shape);
//auto res = adapt((uint8_t *)m.data, m.total() * m.channels(), no_ownership(), shape);
cout << typeid(res).name() << endl;
cout << res << endl;
注意: adapt 的几个参数. 第一个参数需要表明 mat 中数据的类型,如果有时候转换结果不对,那就注意检查这个参数。 第二个参数需要表明 mat 的数据占用的元素数目,注意不是内存大小。 第三个参数照抄即可 第四个参数非常重要,指定转换后的矩阵维度布局。比如上面代码里面 三种 shape,输出的结果也是不一样的。
vector<int> shape = {m.rows, m.cols, m.channels()};
{{{1},
{0},
{0},
{0}},
{{0},
{1},
{0},
{0}},
{{0},
{0},
{1},
{0}},
{{0},
{0},
{0},
{1}}}
vector<int> shape = {m.rows, m.cols};
{{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}}
vector<int> shape = {m.rows * m.cols};
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}
参考: https://github.com/xtensor-stack/xtensor/issues/1220
3. xarray 的矩阵可以直接相加
Mat m = Mat::eye(4, 4, CV_8U);
vector<int> shape = {m.rows, m.cols};
auto res = adapt((uint8_t *)m.data, m.total() * m.channels(), no_ownership(), shape);
//xarray<uint8_t> a2 = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
xarray<uint8_t> a2 = {1, 2, 3, 4};
auto a3 = res + a2;
cout << a3 << endl;
注意: 相加的矩阵,要不就维度和尺寸一致,要不其中一个是另外一个的子维度,否则相加会除错。 参考: https://xtensor.readthedocs.io/en/latest/adaptor.html
4. 初始化矩阵的时候,如果数值后面增加小数点,表明这个数值是浮点数。
auto img = xrray<double>({100., 5.})
5. 转换矩阵数值类型,比如把 int 转为 float32
xt::cast<float32_t>(arr)
6. 切片
#include "xtensor/xview.hpp"
cout << "col: 479: " << view(imgTmp, all(), 479, all()) << endl;
cout << "row: 639: " << view(imgTmp, 639, all(), all()) << endl;
cout << "row: 1079: " << view(imgTmp, 1079, all(), all()) << endl;
7. has no member named ‘strides’ resize_container(temp_strides, e.strides().size()) 这个报错是因为类型使用的是 auto 类型。
auto c = a - at;
auto b = xt::transpose(c, {2, 0, 1}); // error
改为类似下面这样明确类型就可以了,否则 auto 返回回来的可能只是一个中间的类型:
xarray<float32_t> c = a - at;
auto b = xt::transpose(c, {2, 0, 1}); // error
参考: https://github.com/xtensor-stack/xtensor/issues/1710
8. xarray 转换 opencv 或其他 c++ 的容器。
my_array.data()
是数据,my_array.dimension()
是维度, opencv 可以使用 cv::Mat::Mat(int ndims, const int * sizes, int type, void * data, const size_t * steps = 0)
来生成相应的类型。
想要获得大小:
std::vector<int> shape(my_array.shape().begin(), my_array.shape().end());
const int* shape_ptr = shape.data();
参考: https://github.com/xtensor-stack/xtensor/issues/1286
9. iterator
#include <xtensor/xarray.hpp>
#include <xtensor/xio.hpp>
#include <xtensor/xaxis_slice_iterator.hpp>
#include <xtensor/xaxis_iterator.hpp>
void testAxisSlice0(xarray<int> & a)
{
cout << "=== slice axis 0 ===" << endl;
auto iter = axis_slice_begin(a, 0);
auto end = axis_slice_end(a, 0);
while(iter != end)
{
std::cout << *iter++ << std::endl;
cout << "------" << endl;
}
}
void testAxisSlice1(xarray<int> & a)
{
cout << "=== slice axis 1 ===" << endl;
auto iter = axis_slice_begin(a, 1u);
auto end = axis_slice_end(a, 1u);
while(iter != end)
{
std::cout << *iter++ << std::endl;
cout << "------" << endl;
}
}
void testAxisSlice2(xarray<int> & a)
{
cout << "=== slice axis 2 ===" << endl;
auto iter = axis_slice_begin(a, 2u);
auto end = axis_slice_end(a, 2u);
while(iter != end)
{
std::cout << *iter++ << std::endl;
cout << "------" << endl;
}
}
void testAxis0(xarray<int> & a)
{
cout << "=== axis 0 ===" << endl;
auto iter = axis_begin(a, 0);
auto end = axis_end(a, 0);
while(iter != end)
{
std::cout << *iter++ << std::endl;
cout << "------" << endl;
}
}
void testAxis1(xarray<int> & a)
{
cout << "=== axis 1 ===" << endl;
auto iter = axis_begin(a, 1u);
auto end = axis_end(a, 1u);
while(iter != end)
{
std::cout << *iter++ << std::endl;
cout << "------" << endl;
}
}
void testAxis2(xarray<int> & a)
{
cout << "=== axis 2 ===" << endl;
auto iter = axis_begin(a, 2u);
auto end = axis_end(a, 2u);
while(iter != end)
{
std::cout << *iter++ << std::endl;
cout << "------" << endl;
}
}
void test(void)
{
xarray<int> a = {{{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}},
{{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24}}};
testAxisSlice0(a);
testAxisSlice1(a);
testAxisSlice2(a);
testAxis0(a);
testAxis1(a);
testAxis2(a);
}
=== slice axis 0 ===
{ 1, 13}
------
{ 2, 14}
------
{ 3, 15}
------
{ 4, 16}
------
{ 5, 17}
------
{ 6, 18}
------
{ 7, 19}
------
{ 8, 20}
------
{ 9, 21}
------
{10, 22}
------
{11, 23}
------
{12, 24}
------
=== slice axis 1 ===
{1, 5, 9}
------
{ 2, 6, 10}
------
{ 3, 7, 11}
------
{ 4, 8, 12}
------
{13, 17, 21}
------
{14, 18, 22}
------
{15, 19, 23}
------
{16, 20, 24}
------
=== slice axis 2 ===
{1, 2, 3, 4}
------
{5, 6, 7, 8}
------
{ 9, 10, 11, 12}
------
{13, 14, 15, 16}
------
{17, 18, 19, 20}
------
{21, 22, 23, 24}
------
=== axis 0 ===
{{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9, 10, 11, 12}}
------
{{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24}}
------
=== axis 1 ===
{{ 1, 2, 3, 4},
{13, 14, 15, 16}}
------
{{ 5, 6, 7, 8},
{17, 18, 19, 20}}
------
{{ 9, 10, 11, 12},
{21, 22, 23, 24}}
------
=== axis 2 ===
{{ 1, 5, 9},
{13, 17, 21}}
------
{{ 2, 6, 10},
{14, 18, 22}}
------
{{ 3, 7, 11},
{15, 19, 23}}
------
{{ 4, 8, 12},
{16, 20, 24}}
------
10. clip 用于限制矩阵数值的上限和下限。
参考: https://xtensor.readthedocs.io/en/latest/api/basic_functions.html?highlight=clip#_CPPv4I000EN2xt4clipEDaRR2E1RR2E2RR2E3 https://xtensor.readthedocs.io/en/latest/quickref/math.html?highlight=clip#basic-functions
11. masked_view 这个和 numpy 中的有些不太一样,numpy 中只显示 mask 之后的, xtensor 对于 mask 的数据显示 masked,并没有进行剔除。
参考:https://xtensor.readthedocs.io/en/latest/view.html?highlight=mask#masked-view
12. filter 用于过滤满足条件的数据,这个条件可以是本矩阵的,也可以是其他矩阵的。
auto probs_filter = filter(probs, probs > prob_threshold);
indexes = filter(indexes, iou <= iou_threshold);
13. index_view 用于提取指定位置的数据组成矩阵。
14. ravel_indices, flatten_indices
15. reshape 矩阵重新排列
参考: https://xtensor.readthedocs.io/en/latest/quickref/basic.html?highlight=reshape#reshape
16. Concatenate 矩阵拼接
参考: https://xtensor.readthedocs.io/en/latest/quickref/builder.html?highlight=concatenate#concatenate
17. argsort 返回从小到大的索引值
18. ellipsis()
主要用于配合 strided_view。
参考: https://xtensor.readthedocs.io/en/latest/api/xview.html?highlight=ellipsis#_CPPv4N2xt8ellipsisEv https://xtensor.readthedocs.io/en/latest/view.html?highlight=strided_view#strided-views
19. range 用于范围,注意如果要使用 _
这个,那么需要 using namespace xt::placeholders; // to enable _ syntax
参考: https://xtensor.readthedocs.io/en/latest/api/xview.html?highlight=range#_CPPv4I00EN2xt5rangeEDa1A1B
20. 提取数据不能直接用 at 等,只能用 begin, end 等迭代器。
21. 获得矩阵的 shape, 维度等。
xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
auto size = a.size(); // size = 6
auto dim = a.dimension(); // dim = 2
auto shape = a.shape(); // shape = {2, 3}
auto sh1 = a.shape(1); // sh1 = 3