0x0 EAIDK310板子初上手
前两周收到EAIDK310板子,板子做工不错,设计紧凑。主控芯片使用Rockchip的RK3228H,四核Cortext-A53,Mali 450MP2,还支持USB3.0、2.4g/5g双频Wifi等强大的连接能力。
板子结构尺寸和树莓派3是完全兼容的,使用之前树莓派3的盒子装上去灰常的合适,哈哈哈~
经过两周的使用感觉很不错,运行稳定。用Tengine框架尝试跑了几个模型,根据官方提供文档和代码示例上手还是比较容易的,这次先发OpenPose项目分享给大家。
代码已经上传到github上,获取地址在这里。
0x1 环境准备
Tengine版本
本项目直接使用Tengine 1.7.1内测版本,想要试用的同学可以向官方申请。
有试了一下直接使用从官网下载的1.0版本,也是可以转换成功的,openpose模型的算子Tengine1.0应该就能支持。
模型下载
OpenPose原始模型可以从这里下载:
prototxt
caffemodel
其中,本项目将prototxt的输入层修改为160x160。
模型转换
使用以下命令将OpenPose原始的Caffe模型转换为Tengine模型:
./convert_model_to_tm -f caffe -p pose_deploy_linevec.prototxt -m pose_iter_440000.caffemodel -o openpose.tm
0x2 代码编写
初始化和加载模型
Tengine初始化和加载模型的代码基本和classification
示例程序一样,代码片段如下所示:
// init tengine
init_tengine();
if(request_tengine_version("0.9") < 0)
return false;
// load model
graph_t graph = nullptr;
graph = create_graph(nullptr, model_format, model_file);
if(!graph)
{
std::cerr << "Create graph0 failed.\n";
std::cout << "errno:" << get_tengine_errno() << "\n";
return false;
}
// input
int img_size = img_h * img_w * 3;
int dims[] = {1, 3, img_h, img_w};
float* input_data = ( float* )malloc(sizeof(float) * img_size);
tensor_t input_tensor = get_graph_input_tensor(graph, 0, 0);
set_tensor_shape(input_tensor, dims, 4);
// prerun
int ret = prerun_graph(graph);
if(-1 == ret)
{
std::cout << " prerun graph failed \n";
return false;
}
其中create_graph传入的参数model_format
为tengine
,model_file
为openpose.tm模型文件路径。
输入数据前处理
数据前处理包括图像缩放、bgr->rgb转换以及mean和scale的处理。处理函数和classification
示例一样。
void get_input_data(const char* image_file, float* input_data, const int img_h, const int img_w, const float* mean,
const float scale)
{
image img_o = imread(image_file);
if(img_o.data == NULL)
{
std::cerr << "Failed to read image file " << image_file << ".\n";
return;
}
image img = resize_image(img_o, img_w, img_h);
img = rgb2bgr_premute(img);
int hw = img_h * img_w;
for(int h = 0; h < img_h; h++)
{
for(int w = 0; w < img_w; w++)
{
for(int c = 0; c < 3; c++)
{
input_data[c * hw + h * img_w + w] =
(img.data[c * hw + h * img_w + w] - mean[c]) * scale;
}
}
}
}
其中传入的目标缩放宽高设为160,mean和scale需要分别设置成0 0 0
和1.0/255
。
模型推理
接下来就是设置模型输入Tensor、进行模型推理和获取输出Tensor数据了,代码如下所示:
get_input_data(image_file, input_data, img_h, img_w, mean, scale);
set_tensor_buffer(input_tensor, input_data, img_size * 4);
run_graph(graph, 1);
tensor_t output_tensor = get_graph_output_tensor(graph, 0, 0);
float* data = ( float* )get_tensor_buffer(output_tensor);
输出后处理
OpenPose模型推理的输出Tensor数据只是一个热图(heatmap),还需要进行缩放、滤波、关键点检测和获取有效连接等处理才能最后得到输出的点。
后处理代码根据网上开源的opencv版本(地址)进行修改,网上有和该代码相应的资料,感兴趣的同学可以去学习(地址),这里就不详细介绍后处理的流程。
0x3 运行效果
下面是对一些图片的运行效果,目前在EAIDK310上用float32跑速度会有点慢,下一步打算对模型进行量化来提升速度。