类似于 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}}
------

参考: https://xtensor.readthedocs.io/en/latest/quickref/iterator.html?highlight=iter#n-1-dimensional-iteration

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

参考: https://xtensor.readthedocs.io/en/latest/api/xindex_view.html?highlight=filter#_CPPv4I_11layout_type00EN2xt6filterEDaRR1ERR1O

13. index_view 用于提取指定位置的数据组成矩阵。

参考: https://xtensor.readthedocs.io/en/latest/api/xindex_view.html?highlight=index_view#_CPPv4I00EN2xt10index_viewEDaRR1ERR1I

14. ravel_indices, flatten_indices

参考: https://xtensor.readthedocs.io/en/latest/indices.html?highlight=view#d-arrays-array-indices-flat-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 返回从小到大的索引值

参考: https://xtensor.readthedocs.io/en/latest/api/xsort.html?highlight=argsort#_CPPv4I0EN2xt7argsortEDaRK11xexpressionI1EENSt9ptrdiff_tE

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

参考: https://xtensor.readthedocs.io/en/latest/quickref/basic.html?highlight=dimension#shape-dimension-size

标签: math

添加新评论