SOPHON OpenCV中Mat是如何分配设备内存和系统内存及相关问题

SOPHON OpenCV中Mat是如何分配设备内存和系统内存的

因为受设计影响,这个问题细节比较多,主要从三方面能解释。

  1. 在SoC模式下,设备内存和系统内存是同一份物理内存,通过操作系统的ION内存进行管理,系统内存是ION内存的mmap获得。在pcie模式下,设备内存和系统内存是两份物理内存,设备内存指BM168x卡上的内存,系统内存指服务器上操作系统内存。如果用户想只开辟系统内存,和开源opencv保持一致,可 以参见FAQ26的回答。

  2. 在Sophon OpenCV中默认会同时开辟设备内存和系统内存,其中系统内存放在mat.u->data或mat.data中,设备内存放在mat.u->addr中。只有以下几种情况会不开辟设备内存,而仅提供系统内存:

    • 当data由外部开辟并提供给mat的时候。即用以下方式声明的时候:
      Mat mat(h, w, type, data); 或 mat.create(h, w, type, data);

    • 在SoC模式下,当type不属于(CV_8UC3, CV_32FC1, CV_32FC3)其中之一的时候。这里特别注意CV_8UC1是不开辟的,这是为了保证我们的opencv能够通过开源opencv的opencv_test_core的一致性验证检查。

    • 当宽或者高小于16的时候。因为这类宽高,硬件不支持

  3. 在BM1682和BM1684的SoC模式下,mat分配的CV_8UC3类型的设备内存会自动做64对齐,即分配的内存大小一定是64对齐的(注意:仅对SoC模式的CV_8UC3而言,且仅对BM1684/BM1682芯片)。在PCIE模式下,分配的内存是byte对齐的。

相关问题:

1. OpenCV中默认是使用ION内存作为MAT的data空间,如何指定Mat对象基于system memory内存去创建使用

using namespace cv;
Mat m;
m.allocator = m.getDefaultAllocator();     // get system allocator

然后就可以正常调用各种mat函数了,如m.create() m.copyto(),后面就会按照指定的allocator来分配内存了

m.allocator = hal::getDefaultAllocator();  // get ion allocator

就又可以恢复使用ION内存分配器来分配内存。

2. 在SoC模式下,OpenCV在使用8UC1 Mat的时候报错,而当Mat格式为8UC3的时候,同样的程序完全工作正常:

在SoC模式下,默认创建的8UC1 Mat是不分配设备内存的。因此当需要用到硬件加速的时候,比如推理,bmcv操作等,就会导致各种内存异常错误。

参考问题 1. 指定8UC1 Mat在创建的时候,内部使用ion分配器去分配内存。如下所示:

cv::Mat gray_mat;
gray_mat.allocator = hal::getAllocator();
gray_mat.create(h, w, CV_8UC1);

3. SoC模式使用cv::Mat的数据地址初始化另外一个cv::Mat时有可能会出现乱码

SoC模式使用cv::Mat的数据地址初始化另外一个cv::Mat 时需要指定_step,即

cv::Mat image_temp_1(image_ost.rows,image_ost.cols,CV_8UC3,image_ost.data,image_ost.step[0]);

4. SoC模式对cv::Mat的内存进行操作

SoC模式下面,cv::Mat的内存需要64字节对齐,所以cv::Mat的内存长度不是width3height,而是stepheight,如果原始图像满足64字节对齐,那么step=width3

5. Mat创建失败,提示“terminate called after throwing an instance of ‘cv::Exception’ what(): OpenCV(4.1.0) …… matrix.cpp:452: error: (-215:Assertion failed) u != 0 in function ‘creat’”

这种错误主要是设备内存分配失败。失败的原因有两种:

  1. 句柄数超过系统限制,原因有可能是因为句柄泄漏,或者系统句柄数设置过小,可以用如下方法确认:
    查看系统定义的最大句柄数:
    ulimit -n
    
    查看当前进程所使用的句柄数:
    lsof -n|awk{print $2}|sort|uniq -c|sort -nr|more
    
  2. 设备内存不够用。可以用如下方法确认:
    SOC模式下:
    cat /sys/kernel/debug/ion/bm_vpp_heap_dump/summary
    
    PCIE模式下:
    bm-smi工具可以查看设备内存空间

解决方案:

在排除代码本身的内存泄漏或者句柄泄漏问题后,可以通过加大系统最大句柄数来解决句柄的限制问题:ulimit -HSn 65536
设备内存不够就需要通过优化程序来减少对设备内存的占用,或者通过修改dts文件中的内存布局来增加对应的设备内存。详细可以参考SM5用户手册中的说明。

6. 用已有Mat的内存数据的宽高去创建新的Mat后,新Mat保存的图像数据错行导致显示不正常

保存的图像错行,通常是由于Mat中step信息丢失所造成。
一般用已有Mat去生成一个新Mat,并且要求内存复用时,可以直接赋值给新的Mat来简单实现,如 Mat1 = Mat2.

但在某些情况下,比如有些客户受限于架构,函数参数只能用C风格的指针传递,就只能用Mat中的data指针,rows,cols成员来重新恢复这个Mat。 这时候就需要注意step变量的设置,在默认情况下是AUTO_STEP配置,即每行数据没有填充数据。但是在很多种情况下,经过opencv处理后,会导致每行出现填充数据。如:

  1. soc模式下,我们的Mat考虑执行效率,在创建Mat内存时每行数据会做64字节对齐,以适配硬件加速的需求(仅在soc模式下)。
  2. opencv的固有操作,如这个Mat是另一个Mat的子矩阵(即rect的选定区域),或者其他可能导致填充的操作。
    因此,按照opencv定义,通用处理方式就是在生成新的Mat的时候必须指定step,如下所示:
    cv::Mat image_mat = cv::imread(filename,IMREAD_COLOR,0);
    cv::Mat image_mat_temp(image_mat.rows,image_mat.cols,CV_8UC3,image_mat.data,image_mat.step[0]);
    cv::imwrite("sophgo1.jpg",image_mat_temp);
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值