EASY EAI灵眸科技
直播中

ALSET

3年用户 269经验值
擅长:可编程逻辑,电源/新能源,嵌入式技术,处理器/DSP
私信 关注
[经验]

【EASY EAI Nano开源套件试用体验】4.神经网络框架ncnn的开发测试

【EASY EAI Nano开源套件试用体验】4.神经网络框架ncnn的开发测试
大信(QQ:8125036)

        电子发烧友和灵眸科技退出了EASY EAI Nano开发板试用。该开发板是基于Rockchip的RV1126处理器,是四核32位Cortex®-A7架构,同时集成了2TOPs AI算力的NPU,具备一定神经网络计算能力,因此能够运行一些深度学习的推理程序。
      本次测试目标是在此开发板上进行神经网络框架ncnn的测试开发,测试ncnn在此开发板上的性能与应用。
1.png

一、ncnn简介
     
       ncnn 是腾讯优图推出的在手机端极致优化的高性能神经网络前向计架框架。也能够在移动设备上的高性能神经网络前向计算框架。ncnn 从设计之初深刻考虑移动端的部署和使用。无第三方依赖,跨平台,其中手机端 cpu的速度快于目前所有已知的开源框架。
       基于ncnn,能够将深度学习算法轻松移植到手机端和移动设备上高效执行,开发人工智能应用。以腾讯内部应用为例,ncnn目前已在QQ,Qzone,微信,天天P图等上得到应用。
ncnn支持大部分常用的CNN 网络
Classical CNN: VGG AlexNetGoogleNet Inception …
Practical CNN: ResNetDenseNet SENet FPN …
Light-weight CNN:SqueezeNet MobileNetV1/V2/V3 ShuffleNetV1/V2 MNasNet …
Detection: MTCNN facedetection…
Detection: VGG-SSDMobileNet-SSD SqueezeNet-SSD MobileNetV2-SSDLite …
Detection: Faster-RCNNR-FCN …
Detection: YOLOV2 YOLOV3MobileNet-YOLOV3 …
Segmentation: FCN PSPNetUNet …
具体特性对比与功能在之前文章已经介绍过,这里不在过多的叙述,感兴趣的同学可以参看笔者之前的一个测试报告有详细的各CNN框架比较介绍:
https://bbs.elecfans.com/jishu_2328174_1_1.html
三、交叉编译ncnn
工程地址:githubhttps://github.com/Tencent/ncnn 从该地址拉取到该项目的最新工程源码:
2.png
同时该项目作者nihui大佬也亲自在rv1126板上移植测过过该项目,可以参考她的帖子:
《EASY EAINano (RV1126) 上手指北>
https://zhuanlan.zhihu.com/p/548039018
按帖子内容,很容易在EASY EAI Nano板上移植编译ncnn.
首先按模板编写好编译脚本:build-easyeai-nano.sh
内容如下:
3.png
然后切换到交叉编译环境,再执行该脚本,如下图:
4.png
整个过程大概10分钟左右,就能看到编译出结果了:
5.png
此脚本把cmake和 make 二合一了,一次就能生成目标文件,编译起来非常简单方便。
该编译把ncnn库和测试例程一起编译了,最后把编译的输出结果传到板子上,另外把ncnn的benchmark测试程序所需要的模型资源也传到板子上, 进入到 build/example 下,把所有编译出的例程也传到开发板上。
6.png
四、运行测试ncnn
      编译完成把可执行文件与模型文件复制到开发板里进行测试。
把 build/benchmark 下的benchncn复制到开发板/home/root/ncnn 目录下,同时把工程根目录下的benchmark 目录下所有文件也复制到开发板 /home/root/ncnn目录下,
7.png
然后就可以执行 benchncnn执行文件来测试该板的人工神经网络的计算能力。
先把开发环境下目标文件系统ARM目录下/usr/lib下的libgomp.so.1文件复制到开发板的/usr/lib下。然后在开发板上执行benchncnn,最后执行结果如下图:
8.png
可见该开发板运行ncnn跑分还是很不错的,超过了大多数同配置的硬件,从对各个模型的分值可以评估该开发板的神经网络推理计算能力了。

五、测试ncnn的例程
      进一步在EASYEAI Nano开发板上测试ncnn工程带的应用例子,这测试列子在开发板文件如下:
9.png

另外这些测试用例在运行时,需要相应的模型资源支持,这些模型在这个地址下可以下载到:
https://github.com/nihui/ncnn-assets/tree/master/models
1. 测试人脸识别
准备被测试图片face5-test.jpg,传到上ncnn当前目录下
10.png
并且下载好mnet.25-opt.param和mnet.25-opt.bin文件到 ncnn当前目录下,然后执行一下命令:
./retinafaceface5-test.jpg
运行速度非常快,瞬间就返回了识别结果,输出结果如下图
11.png
同时输出叠加标记结果的图 image.png:
12.png
2. 测试图片内容多目标识别
准备一张多目标物体的图,如下:
13.png
测试图片内容识别,先用上面的图,再使用 squeezenetssd来执行。执行前先下载 squeezenet_ssd_voc.bin 和 squeezenet_ssd_voc.param 到板上ncnn当前目录下,然后执行:
./squeezenetssd ./test.jpg
大约半秒左右输出结果如图:
14.png
输出的分类编号,可见代码的定义:
15.png
同时输出了识别结果图:
16.png
可见该模型识别时,图中的小狗没有识别出来。
再测试另外一个模型;
17.png
识别结果图:
18.png
识别大约2秒,除了狗识别错误,其它都正确,效果也比较理想。
同样测试 yolov5_pnnx ,命令行
./yolov5_pnnx ./testting.jpg
识别结果如图:
19.png
20.png
这次识别狗正确,但使用时间比yolov7 稍长。

六、整合开发ncnn应用

      结合Easy-EAI的摄像头采集和屏幕显示的RkMedia例程,在整合ncnn人脸识别程序,进一步改造成一个完成的ncnn的应用。
      这个引用在ncnn的scrfd例程基础上进行修改, 新文件为 easy_scrfd.cpp,因为开发板上的mipi 摄像头不方便拍摄,这里使用 usb 摄像头。
代码如下:
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.

  14. #include "net.h"

  15. #if defined(USE_NCNN_SIMPLEOCV)
  16. #include "simpleocv.h"
  17. #else
  18. #include
  19. #include
  20. #include
  21. #endif
  22. #include
  23. #include
  24. #include
  25. #include
  26. #include

  27. struct FaceObject
  28. {
  29.         cv::Rect_ rect;
  30.         float prob;
  31. };

  32. static inline float intersection_area(const FaceObject& a, const FaceObject& b)
  33. {
  34.         cv::Rect_ inter = a.rect & b.rect;
  35.         return inter.area();
  36. }

  37. static void qsort_descent_inplace(std::vector& faceobjects, int left, int right)
  38. {
  39.         int i = left;
  40.         int j = right;
  41.         float p = faceobjects[(left + right) / 2].prob;

  42.         while (i <= j)
  43.         {
  44.                 while (faceobjects[i].prob > p)
  45.                         i++;

  46.                 while (faceobjects[j].prob < p)
  47.                         j--;

  48.                 if (i <= j)
  49.                 {
  50.                         // swap
  51.                         std::swap(faceobjects[i], faceobjects[j]);

  52.                         i++;
  53.                         j--;
  54.                 }
  55.         }

  56. #pragma omp parallel sections
  57.         {
  58. #pragma omp section
  59.                 {
  60.                         if (left < j) qsort_descent_inplace(faceobjects, left, j);
  61.                 }
  62. #pragma omp section
  63.                 {
  64.                         if (i < right) qsort_descent_inplace(faceobjects, i, right);
  65.                 }
  66.         }
  67. }

  68. static void qsort_descent_inplace(std::vector& faceobjects)
  69. {
  70.         if (faceobjects.empty())
  71.                 return;

  72.         qsort_descent_inplace(faceobjects, 0, faceobjects.size() - 1);
  73. }

  74. static void nms_sorted_bboxes(const std::vector& faceobjects, std::vector& picked, float nms_threshold)
  75. {
  76.         picked.clear();

  77.         const int n = faceobjects.size();

  78.         std::vector areas(n);
  79.         for (int i = 0; i < n; i++)
  80.         {
  81.                 areas[i] = faceobjects[i].rect.area();
  82.         }

  83.         for (int i = 0; i < n; i++)
  84.         {
  85.                 const FaceObject& a = faceobjects[i];

  86.                 int keep = 1;
  87.                 for (int j = 0; j < (int)picked.size(); j++)
  88.                 {
  89.                         const FaceObject& b = faceobjects[picked[j]];

  90.                         // intersection over union
  91.                         float inter_area = intersection_area(a, b);
  92.                         float union_area = areas[i] + areas[picked[j]] - inter_area;
  93.                         //             float IoU = inter_area / union_area
  94.                         if (inter_area / union_area > nms_threshold)
  95.                                 keep = 0;
  96.                 }

  97.                 if (keep)
  98.                         picked.push_back(i);
  99.         }
  100. }

  101. // insightface/detection/scrfd/mmdet/core/anchor/anchor_generator.py gen_single_level_base_anchors()
  102. static ncnn::Mat generate_anchors(int base_size, const ncnn::Mat& ratios, const ncnn::Mat& scales)
  103. {
  104.         int num_ratio = ratios.w;
  105.         int num_scale = scales.w;

  106.         ncnn::Mat anchors;
  107.         anchors.create(4, num_ratio * num_scale);

  108.         const float cx = 0;
  109.         const float cy = 0;

  110.         for (int i = 0; i < num_ratio; i++)
  111.         {
  112.                 float ar = ratios[i];

  113.                 int r_w = round(base_size / sqrt(ar));
  114.                 int r_h = round(r_w * ar); //round(base_size * sqrt(ar));

  115.                 for (int j = 0; j < num_scale; j++)
  116.                 {
  117.                         float scale = scales[j];

  118.                         float rs_w = r_w * scale;
  119.                         float rs_h = r_h * scale;

  120.                         float* anchor = anchors.row(i * num_scale + j);

  121.                         anchor[0] = cx - rs_w * 0.5f;
  122.                         anchor[1] = cy - rs_h * 0.5f;
  123.                         anchor[2] = cx + rs_w * 0.5f;
  124.                         anchor[3] = cy + rs_h * 0.5f;
  125.                 }
  126.         }

  127.         return anchors;
  128. }

  129. static void generate_proposals(const ncnn::Mat& anchors, int feat_stride, const ncnn::Mat& score_blob, const ncnn::Mat& bbox_blob, float prob_threshold, std::vector& faceobjects)
  130. {
  131.         int w = score_blob.w;
  132.         int h = score_blob.h;

  133.         // generate face proposal from bbox deltas and shifted anchors
  134.         const int num_anchors = anchors.h;

  135.         for (int q = 0; q < num_anchors; q++)
  136.         {
  137.                 const float* anchor = anchors.row(q);

  138.                 const ncnn::Mat score = score_blob.channel(q);
  139.                 const ncnn::Mat bbox = bbox_blob.channel_range(q * 4, 4);

  140.                 // shifted anchor
  141.                 float anchor_y = anchor[1];

  142.                 float anchor_w = anchor[2] - anchor[0];
  143.                 float anchor_h = anchor[3] - anchor[1];

  144.                 for (int i = 0; i < h; i++)
  145.                 {
  146.                         float anchor_x = anchor[0];

  147.                         for (int j = 0; j < w; j++)
  148.                         {
  149.                                 int index = i * w + j;

  150.                                 float prob = score[index];

  151.                                 if (prob >= prob_threshold)
  152.                                 {
  153.                                         // insightface/detection/scrfd/mmdet/models/dense_heads/scrfd_head.py _get_bboxes_single()
  154.                                         float dx = bbox.channel(0)[index] * feat_stride;
  155.                                         float dy = bbox.channel(1)[index] * feat_stride;
  156.                                         float dw = bbox.channel(2)[index] * feat_stride;
  157.                                         float dh = bbox.channel(3)[index] * feat_stride;

  158.                                         // insightface/detection/scrfd/mmdet/core/bbox/transforms.py distance2bbox()
  159.                                         float cx = anchor_x + anchor_w * 0.5f;
  160.                                         float cy = anchor_y + anchor_h * 0.5f;

  161.                                         float x0 = cx - dx;
  162.                                         float y0 = cy - dy;
  163.                                         float x1 = cx + dw;
  164.                                         float y1 = cy + dh;

  165.                                         FaceObject obj;
  166.                                         obj.rect.x = x0;
  167.                                         obj.rect.y = y0;
  168.                                         obj.rect.width = x1 - x0 + 1;
  169.                                         obj.rect.height = y1 - y0 + 1;
  170.                                         obj.prob = prob;

  171.                                         faceobjects.push_back(obj);
  172.                                 }

  173.                                 anchor_x += feat_stride;
  174.                         }

  175.                         anchor_y += feat_stride;
  176.                 }
  177.         }
  178. }

  179. static int detect_scrfd(const cv::Mat& bgr, std::vector& faceobjects)
  180. {
  181.         ncnn::Net scrfd;

  182.         scrfd.opt.use_vulkan_compute = true;

  183.         // model is converted from
  184.         // https://github.com/deepinsight/insightface/tree/master/detection/scrfd
  185.         // the ncnn model https://github.com/nihui/ncnn-assets/tree/master/models
  186.         if (scrfd.load_param("scrfd_500m-opt2.param"))
  187.                 exit(-1);
  188.         if (scrfd.load_model("scrfd_500m-opt2.bin"))
  189.                 exit(-1);

  190.         int width = bgr.cols;
  191.         int height = bgr.rows;

  192.         // insightface/detection/scrfd/configs/scrfd/scrfd_500m.py
  193.         const int target_size = 640;
  194.         const float prob_threshold = 0.3f;
  195.         const float nms_threshold = 0.45f;

  196.         // pad to multiple of 32
  197.         int w = width;
  198.         int h = height;
  199.         float scale = 1.f;
  200.         if (w > h)
  201.         {
  202.                 scale = (float)target_size / w;
  203.                 w = target_size;
  204.                 h = h * scale;
  205.         }
  206.         else
  207.         {
  208.                 scale = (float)target_size / h;
  209.                 h = target_size;
  210.                 w = w * scale;
  211.         }

  212.         ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR2RGB, width, height, w, h);

  213.         // pad to target_size rectangle
  214.         int wpad = (w + 31) / 32 * 32 - w;
  215.         int hpad = (h + 31) / 32 * 32 - h;
  216.         ncnn::Mat in_pad;
  217.         ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT, 0.f);

  218.         const float mean_vals[3] = { 127.5f, 127.5f, 127.5f };
  219.         const float norm_vals[3] = { 1 / 128.f, 1 / 128.f, 1 / 128.f };
  220.         in_pad.substract_mean_normalize(mean_vals, norm_vals);

  221.         ncnn::Extractor ex = scrfd.create_extractor();

  222.         ex.input("input.1", in_pad);

  223.         std::vector faceproposals;

  224.         // stride 32
  225.         {
  226.                 ncnn::Mat score_blob, bbox_blob;
  227.                 ex.extract("412", score_blob);
  228.                 ex.extract("415", bbox_blob);

  229.                 const int base_size = 16;
  230.                 const int feat_stride = 8;
  231.                 ncnn::Mat ratios(1);
  232.                 ratios[0] = 1.f;
  233.                 ncnn::Mat scales(2);
  234.                 scales[0] = 1.f;
  235.                 scales[1] = 2.f;
  236.                 ncnn::Mat anchors = generate_anchors(base_size, ratios, scales);

  237.                 std::vector faceobjects32;
  238.                 generate_proposals(anchors, feat_stride, score_blob, bbox_blob, prob_threshold, faceobjects32);

  239.                 faceproposals.insert(faceproposals.end(), faceobjects32.begin(), faceobjects32.end());
  240.         }

  241.         // stride 16
  242.         {
  243.                 ncnn::Mat score_blob, bbox_blob;
  244.                 ex.extract("474", score_blob);
  245.                 ex.extract("477", bbox_blob);

  246.                 const int base_size = 64;
  247.                 const int feat_stride = 16;
  248.                 ncnn::Mat ratios(1);
  249.                 ratios[0] = 1.f;
  250.                 ncnn::Mat scales(2);
  251.                 scales[0] = 1.f;
  252.                 scales[1] = 2.f;
  253.                 ncnn::Mat anchors = generate_anchors(base_size, ratios, scales);

  254.                 std::vector faceobjects16;
  255.                 generate_proposals(anchors, feat_stride, score_blob, bbox_blob, prob_threshold, faceobjects16);

  256.                 faceproposals.insert(faceproposals.end(), faceobjects16.begin(), faceobjects16.end());
  257.         }

  258.         // stride 8
  259.         {
  260.                 ncnn::Mat score_blob, bbox_blob;
  261.                 ex.extract("536", score_blob);
  262.                 ex.extract("539", bbox_blob);

  263.                 const int base_size = 256;
  264.                 const int feat_stride = 32;
  265.                 ncnn::Mat ratios(1);
  266.                 ratios[0] = 1.f;
  267.                 ncnn::Mat scales(2);
  268.                 scales[0] = 1.f;
  269.                 scales[1] = 2.f;
  270.                 ncnn::Mat anchors = generate_anchors(base_size, ratios, scales);

  271.                 std::vector faceobjects8;
  272.                 generate_proposals(anchors, feat_stride, score_blob, bbox_blob, prob_threshold, faceobjects8);

  273.                 faceproposals.insert(faceproposals.end(), faceobjects8.begin(), faceobjects8.end());
  274.         }

  275.         // sort all proposals by score from highest to lowest
  276.         qsort_descent_inplace(faceproposals);

  277.         // apply nms with nms_threshold
  278.         std::vector picked;
  279.         nms_sorted_bboxes(faceproposals, picked, nms_threshold);

  280.         int face_count = picked.size();

  281.         faceobjects.resize(face_count);
  282.         for (int i = 0; i < face_count; i++)
  283.         {
  284.                 faceobjects[i] = faceproposals[picked[i]];

  285.                 // adjust offset to original unpadded
  286.                 float x0 = (faceobjects[i].rect.x - (wpad / 2)) / scale;
  287.                 float y0 = (faceobjects[i].rect.y - (hpad / 2)) / scale;
  288.                 float x1 = (faceobjects[i].rect.x + faceobjects[i].rect.width - (wpad / 2)) / scale;
  289.                 float y1 = (faceobjects[i].rect.y + faceobjects[i].rect.height - (hpad / 2)) / scale;

  290.                 x0 = std::max(std::min(x0, (float)width - 1), 0.f);
  291.                 y0 = std::max(std::min(y0, (float)height - 1), 0.f);
  292.                 x1 = std::max(std::min(x1, (float)width - 1), 0.f);
  293.                 y1 = std::max(std::min(y1, (float)height - 1), 0.f);

  294.                 faceobjects[i].rect.x = x0;
  295.                 faceobjects[i].rect.y = y0;
  296.                 faceobjects[i].rect.width = x1 - x0;
  297.                 faceobjects[i].rect.height = y1 - y0;
  298.         }

  299.         return 0;
  300. }

  301. static void draw_faceobjects(cv::Mat& bgr, const std::vector& faceobjects)
  302. {
  303.         cv::Mat image = bgr.clone();

  304.         for (size_t i = 0; i < faceobjects.size(); i++)
  305.         {
  306.                 const FaceObject& obj = faceobjects[i];

  307.                 fprintf(stderr, "%.5f at %.2f %.2f %.2f x %.2fn", obj.prob,
  308.                         obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);

  309.                 cv::rectangle(image, obj.rect, cv::Scalar(0, 255, 0));

  310.                 char text[256];
  311.                 sprintf(text, "%.1f%%", obj.prob * 100);

  312.                 int baseLine = 0;
  313.                 cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

  314.                 int x = obj.rect.x;
  315.                 int y = obj.rect.y - label_size.height - baseLine;
  316.                 if (y < 0)
  317.                         y = 0;
  318.                 if (x + label_size.width > image.cols)
  319.                         x = image.cols - label_size.width;

  320.                 cv::rectangle(image, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
  321.                         cv::Scalar(255, 255, 255), -1);

  322.                 cv::putText(image, text, cv::Point(x, y + label_size.height),
  323.                         cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
  324.         }

  325.         //cv::imshow("image", image);
  326.         //cv::waitKey(0);
  327.         bgr= image;
  328.         return;
  329. }


  330. #define        DISP_WIDTH                720
  331. #define        DISP_HEIGHT                1280

  332. #define CAMERA_WIDTH        1280
  333. #define CAMERA_HEIGHT        720

  334. #include

  335. static int g_run = 0;

  336. static void sigterm_handler(int sig) {
  337.         fprintf(stderr, "signal %dn", sig);
  338.         g_run = 1;
  339. }

  340. int main(int argc, char** argv)
  341. {
  342.         int ret;
  343.         cv::Mat image;
  344.         std::vector faceobjects;
  345.         if (argc != 2)
  346.         {
  347.                 fprintf(stderr, "Usage: %s [imagepath]n", argv[0]);
  348.                 return -1;
  349.         }

  350.         signal(SIGINT, sigterm_handler);
  351.         const char* imagepath = argv[1];

  352.         ret = disp_init(DISP_WIDTH, DISP_HEIGHT); //RGB888 default
  353.         if (ret) {
  354.                 printf("disp_init error!n");
  355.                 return 0;
  356.         }
  357. #if 1       
  358.   int scrimage_size;
  359.   double fx,fy;
  360.   cv::Mat screen_image;
  361.          
  362.         image = cv::imread(imagepath, 1);
  363.         if (image.empty())
  364.         {
  365.                 fprintf(stderr, "cv::imread %s failedn", imagepath);
  366.                 return -1;
  367.         }

  368.         //printf("image: %d,%dn",image.cols, image.rows);
  369.        
  370.         screen_image = cv::Mat::zeros(DISP_WIDTH, DISP_HEIGHT, CV_8UC3);       
  371.   scrimage_size = DISP_WIDTH*DISP_HEIGHT*3;
  372.   
  373.         detect_scrfd(image, faceobjects);

  374.         draw_faceobjects(image, faceobjects);
  375.   
  376.   fx = DISP_HEIGHT / image.cols ;
  377.   fy = DISP_WIDTH / image.rows ;
  378.   if(fx > fy) fx = fy;
  379.   if(fx < fy) fy = fx;         
  380.   cv::resize(image, image, cv::Size(0,0),fx,fy);
  381.   //printf("image: %d,%dn",image.cols, image.rows);
  382.   
  383.   cv::Mat imgROI = screen_image(cv::Rect((DISP_HEIGHT-image.cols)/2, (DISP_WIDTH -image.rows)/2, image.cols,image.rows));
  384.   cv::addWeighted(imgROI, 0.0, image, 1.0, 0.0 , imgROI); //叠加图片

  385.   cv::rotate(screen_image, screen_image, cv::ROTATE_90_CLOCKWISE);       
  386.         disp_commit(screen_image.data,scrimage_size);   //显示图像       

  387.         while (!g_run) {
  388.                 usleep(10000);
  389.         }
  390.         disp_exit();
  391. #else          

  392.         char* pbuf = NULL;
  393.         int width, height;
  394.         int outimage_size;
  395.         int i, j, k;
  396.         FILE* fp;

  397.         width = CAMERA_WIDTH;
  398.         height = CAMERA_HEIGHT;

  399.         ret = usbcamera_init(USB2_0, USB_DIRECT, CAMERA_HEIGHT, CAMERA_WIDTH, 90);
  400.         if (ret) {
  401.                 printf("usbcamera_init %d, error: %s, %dn", ret, __func__, __LINE__);
  402.                 return -1;
  403.         }
  404.         //image = cv::Mat::zeros(height, width, CV_8UC3);
  405.         usbcamera_preset_fps(5);

  406.         //fp = fopen("./usb_camera.bgr", "w");
  407.         //if (!fp) {
  408.         //        printf("error: %s, %dn", __func__, __LINE__);
  409.         //        ret = -1;
  410.         //        return -1;
  411.         //}

  412.         outimage_size = width * height * 3;
  413.         pbuf = (char*)malloc(outimage_size);

  414.         while (!g_run)
  415.         {
  416.                 ret = usbcamera_getframe(USB2_0, USB_DIRECT, pbuf);
  417.                 if (ret) {
  418.                         printf("error: %s, %dn", __func__, __LINE__);
  419.                         break;
  420.                 }
  421.                
  422.                 image = cv::Mat(height, width, CV_8UC3, pbuf);

  423.                 detect_scrfd(image, faceobjects);
  424.     printf("faceobjects: %d n", faceobjects.size());
  425.    
  426.                 draw_faceobjects(image, faceobjects);

  427.                 //show_image(outimage,0);               
  428.                 disp_commit(image.data, outimage_size);   //显示图像       

  429.                 //fwrite(pbuf, 1, outimage_size, fp);
  430.                 //disp_commit(pbuf, outimage_size); //显示图像       
  431.                 usleep(1000);
  432.         }
  433.         //fclose(fp);
  434.         usbcamera_exit(USB2_0, USB_DIRECT);
  435.         disp_exit();

  436.         free(pbuf);
  437.         pbuf = NULL;
  438. #endif

  439.         return 0;
  440. }
编写cmake 文件
  1. cmake_minimum_required(VERSION 2.8.4)

  2. project(ncnn-demo)

  3. set(CMAKE_SYSTEM_NAME Linux)
  4. set(CMAKE_CROSSCOMPILING TRUE)

  5. set(CMAKE_C_COMPILER "arm-linux-gnueabihf-gcc")
  6. set(CMAKE_CXX_COMPILER "arm-linux-gnueabihf-g++")
  7. # -I
  8. set(inc ./)

  9. include_directories(
  10.         ./include/ncnn/
  11.          /mnt/hgfs/EASY-EAI-NANO/proj/EASY-EAI-Toolkit-C-Demo/easyeai-api/peripheral_api/display/
  12.          /mnt/hgfs/EASY-EAI-NANO/proj/EASY-EAI-Toolkit-C-Demo/easyeai-api/peripheral_api/camera/
  13. )

  14. # -L
  15. link_directories(
  16.    ./lib/
  17.    /mnt/hgfs/EASY-EAI-NANO/proj/EASY-EAI-Toolkit-C-Demo/easyeai-api/peripheral_api/display/
  18.    /mnt/hgfs/EASY-EAI-NANO/proj/EASY-EAI-Toolkit-C-Demo/easyeai-api/peripheral_api/camera/
  19.    /opt/rv1126_rv1109_sdk/buildroot/output/rockchip_face_board/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/
  20. )

  21. #--------------------------
  22. # ncnn_app
  23. #--------------------------
  24. add_executable(ncnn-demo ncnn-demo.cpp)                #-o
  25. target_include_directories(ncnn-demo PRIVATE ${inc})        #-I
  26. target_link_libraries(ncnn-demo ncnn pthread -fopenmp easymedia rockchip_mpp rkaiq rga
  27.     -lopencv_calib3d
  28.     -lopencv_core
  29.     -lopencv_dnn
  30.     -lopencv_features2d
  31.     -lopencv_flann
  32.     -lopencv_highgui
  33.     -lopencv_imgcodecs
  34.     -lopencv_imgproc
  35.     -lopencv_ml
  36.     -lopencv_objdetect
  37.     -lopencv_photo
  38.     -lopencv_shape
  39.     -lopencv_stitching
  40.     -lopencv_superres
  41.     -lopencv_videoio
  42.     -lopencv_video
  43.     -lopencv_videostab)        #-l

  44. target_link_libraries(ncnn-demo libdisplay.a libcamera.a)
然后进行编译
21.png
22.png
上传到板子上运行
23.png
最后的测试现场,通过USB 采集画面,在通过scrfd做人脸识别,识别的结果图像显示到LCD屏幕上。
24.png
从测试效果看,验证了从摄像头抓取视频图片,然后再进行scrfd进行人脸识别,再把标记后的图片显示到屏幕上,大概有美秒2帧的速度。分析主要原因在easy包装的摄像头和显示接口与opencv的mat图像转换上,效率很低,在不加人脸识别时,其直接显示的帧率也就3帧左右。而其自带的rkmedia例程则是通过系统的共享内存直接把采集到的图像送到显示驱动,因此效率要高很多。
25.png
26.png

七、ncnn开发测试总结
      通过在Easy-EAI-Nano开发板上对ncnn的benchmark的性能测试来看,该开发板执行ncnn跑分较为不错,对一般的嵌入式神经网络推理来说,已经完全能够满足业务需求。
      在对实际中测试,在具体应用时,还需要进一步的优化,在数据传输,转化等方面做到提高效率,一般是通过rkmedia底层的接口,来实现高效的数据转换,同时在应用中,也可以把推理算法的封装进行优化,把通用的图像格式,转化为硬件支持的数据格式,利用硬件进一步的加速,得到最好的效果。
    Ncnn结合该开发板的其它多媒体能力和网络通信功能,可以开发出多种基于神经网络的边缘应用,而ncnn工程里带有一些各种其它框架模型转化ncnn的工具,也方便将其它模型转化到ncnn上使用,开源社区也提供了非常丰富的资源,非常方便扩展使用。

更多回帖

发帖
×
20
完善资料,
赚取积分