RK3399pro 使用rknn 问题记录

RK3399pro 使用rknn 问题记录

  • 问题1:RK3399pro使用python3读取USB摄像头数据问题
  • 问题2:SSD模型输出之后,后处理时间太长
  • 问题3:优化C++ ——OpenMP使用

问题1:RK3399pro使用python3读取USB摄像头数据问题

  • 基于RK3399pro使用官方fadora系统时候,因为系统配置了MIPI摄像机接口,所以 /dev/video0~video7 接口都被占用了,接入罗技USB摄像头时,自动加载为/dev/video8和video9

    然而使用python3+opencv中,cv2.VideoCaptrue(),无法读取摄像头数据,会出现无图像数据的错误。

    所以选择使用 [python3-v4l2capture](https://github.com/georgexuedz/python3-v4l2capture) 读取摄像头二进制数据,然后使用cv2转换数据格式,转换成opencv所使用的numpy格式。

    经过测试,在RK3399pro上进行格式转化时间约为20ms。
    以下是V4l2调用RK3399pro 使用rknn 问题记录_第1张图片

问题2:SSD模型输出之后,后处理时间太长

  • ssd模型输出两个结果,一个类别,一个坐标位置,均为numpy格式,此时需要遍历numpy以获取最终结果。
    这就存在一个问题,因为python的机制问题,python3的for循环特别慢所以考虑是有pybind11调用C++解决这个问题,把循环放在C++上面,直至返回结果。

在这个过程中使用了pybind11之后,数据格式转换比较麻烦,
方法一:
如:

void aftertreatment(py::array_t<double>& input1)
{
     
    // 获取input1的信息
    //input1输入的是一个python3的numpy.ndarray的二维数组
    py::buffer_info buf1 = input1.request();
    unsigned char* outputClasses = (unsigned char*)buf1.ptr;
    int rows=buf1.shape[0];
    int cols=buf1.shape[1];
    //输出二维数组所有数据
    for (int i=0; i<rows; i++){
     
    	for (int j=0; j<cols; j++){
     
    		printf("%.8lf\t",buf[i*rows+j]);
    		}
    	printf("\n");
    	}
}

其中使用了 py::buffer_info数据类型 ,其结构体如下

struct buffer_info {
         
    void *ptr;                      /* Pointer to buffer */    
    ssize_t itemsize;               /* Size of one scalar */    
    std::string format;             /* Python struct-style format descriptor */    
    ssize_t ndim;                   /* Number of dimensions */    
    std::vector<ssize_t> shape;     /* Buffer dimensions */    
    std::vector<ssize_t> strides;    /* Strides (in bytes) for each index */
};

如此的话可以把二维数组转化成以为数据块,通过计算可以得到相应的位置

方法二:

void aftertreatment(py::array_t<doubler>& input1)
{
     
    // 获取input1的信息
    //input1输入的是一个python3的numpy.ndarray的二维数组
    auto buf1= input1.mutable_unchecked();
    int rows=buf1.shape(0);
    int cols=buf1.shape(1);
    for (int i=0; i<rows; i++){
     
    	for (int j=0; j<cols; j++){
     
    		printf("%.8lf\t",buf1(i,j));
    		}
    	printf("\n");
    	}
}

这个方法比较简单粗暴,直接输出,然后通过便利二维数组的方法遍历数据
调试好C++代码后,使用脚本创建pyd/so库

最后使用rk3399pro的demo,项目example/mobilenet-ssd,完成实现。python3调用C++的后处理程序,相较于python3的后处理程序,需要600+ms,使用pybind11调用C++ 仅需要31ms就可以完成。
代码见附件。

生成python模块(.pyd/.so)方法:

  • 方式1:使用python3脚本创建

    创建文件setup.py

    cmake_minimum_required(VERSION 3.14)
    project(ssd_handle)
    
    add_definitions(-std=c++14)
    add_definitions("-Wall")
    add_definitions(-DUNICODE -D_UUNICODE)
    
    set(CMAKE_BUILD_TYPE"Release")
    if(OPENMP_FOUND)
        message("OPENMP FOUND")
        set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} $({OpenMP_C_FLAGS}")
        set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
        set(CMAKE_EXE_LINKER_FLAGS"${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
    endif()
    
    include_directories(<path_to_pybind11>/include)
    
    find_package(PythonLibs REQUIRED)
    include_directories(${
           PYTHON_INCLUDE_DIRS})
    
    #add_subdirectory(pybind11)
    find_package(pybind11 REQUIRED)
    pybind11_add_module(ssd_handle ssd_handle.cpp)
    

    然后在终端命令编译,会在当前目录下生成 如“ssd_handle.cpython-36m-aarch64-linux-gun.so”之类的文件。

    cmake .
    make
    

python 调用C++代码:

import ssh_handle
result = ssd_handle.aftertreatment(input1)

问题3:优化C++ ——OpenMP使用

目前demo后处理(1917*91次for循环)维维持在31ms,尝试使用openMP优化

#pragma omp parallel num_threads(6)
 {
     
     #pragma omp parallel for
     for(int i=0;i<NUM_RESULTS;i++)
     {
     
     	/*以下内容为for循环内容 自己补充*/
     }   	
 }

参考:
pybind11官方文档
openMP参考博客

附上代码:
问题1代码:test2.py(基于rk3399官方例程:example/mobilenet_v1)
调试完成代码:ssd_handle(基于rk3399官方例程:example/mobilenet_ssd)

你可能感兴趣的:(代码分享,rk3399pro)