回答

收藏

[原创] 【瑞萨AI挑战赛】 部署仪表识别算法方案(一)

瑞萨电子 瑞萨电子 17 人阅读 | 0 人回复 | 2026-03-15

  Renesas RA8 系列(如 RA8M1/RA8D1)是瑞萨面向高端嵌入式场景的 MCU,部署仪表识别算法需结合硬件特性、算法轻量化、工具链适配三大核心环节。
   一、RA8 系列核心特性RA8 :
   CPU:Arm Cortex-M85(最高 480MHz,支持 ARMv8-M 架构、DSP 指令、M-Profile Vector Extension (MVE) 向量扩展);
   AI加速器:集成 CNN 加速器(RA8D1),支持轻量化神经网络推理;
   外设:支持摄像头(CSI/DSI)、LCD 屏、DMA、硬件浮点单元(FPU)







  仪表识别算法通常包含:图像采集→预处理→数字 / 指针识别→结果输出,RA8 可兼顾传统机器视觉(如 OpenCV-Micro)和轻量化 CNN(如 TensorFlow Lite Micro)两种方案。


二、部署步骤,开发环境搭建安装工具链 OpenCV
   2.1 下载并安装瑞萨 e² studio:https://www.renesas.com/cn/zh/software-tool/e-studio
   2.2 安装 RA8 系列 FSP 包(包含底层驱动、中间件):在 e² studio 中通过FSP Installer安装对应型号的 FSP;
   2.3 可选:安装 Arm GNU Toolchain(用于编译轻量化算法)、TensorFlow Lite Micro(TFLM)源码。
   2.4 安装 RT-Thread Studio 详见官网,在SDK 管理器中下载 sdk-bsp-ra8p1-titan-board ,推荐离线导入SDK;
   2.5 安装瑞萨 NPU 驱动组件:在 RT-Thread Studio 的RT-Thread Settings 中,启用 Renesas NPU 驱动、rtsl_ai 人工智能框架;
   2.6 配置编译器:使用 ARM GCC 10.3 以上版本,开启 march=armv8.1-m.main+mve.fp -O3 优化(利用 MVE 向量指令加速预处理)。
三、数字仪表识别(无 NPU,轻量快速)

   核心逻辑:图像预处理→轮廓检测→数字分割→模板匹配,基于 RT-Thread 的cv组件实现:
   核心算法:
  1. <span style="color: rgb(0, 0, 0); font-family: ui-sans-serif, system-ui, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;; font-size: 16px; white-space: pre;">#include <opencv2/opencv.hpp>
  2. #include <opencv2/imgproc/imgproc.hpp>
  3. #include <cmath>
  4. #include <iostream>

  5. using namespace cv;
  6. using namespace std;

  7. // 仪表参数配置(根据实际仪表调整)
  8. const float GAUGE_MIN_ANGLE = 45.0f;   // 指针最小值对应角度(顺时针)
  9. const float GAUGE_MAX_ANGLE = 315.0f; // 指针最大值对应角度
  10. const float GAUGE_MIN_VALUE = 0.0f;    // 仪表最小值
  11. const float GAUGE_MAX_VALUE = 100.0f;  // 仪表最大值
  12. const int GAUGE_RADIUS = 150;          // 表盘半径(像素)

  13. // 计算两点间角度
  14. float calculateAngle(Point center, Point point) {
  15.     float dx = point.x - center.x;
  16.     float dy = point.y - center.y;
  17.     float angle = atan2(dy, dx) * 180.0f / CV_PI;
  18.     if (angle < 0) angle += 360.0f;
  19.     return angle;
  20. }

  21. // 角度转仪表数值
  22. float angleToValue(float angle) {
  23.     // 角度范围映射到数值范围
  24.     if (angle < GAUGE_MIN_ANGLE) angle += 360.0f;
  25.     if (angle > GAUGE_MAX_ANGLE) angle = GAUGE_MAX_ANGLE;
  26.    
  27.     float ratio = (angle - GAUGE_MIN_ANGLE) / (GAUGE_MAX_ANGLE - GAUGE_MIN_ANGLE);
  28.     return GAUGE_MIN_VALUE + ratio * (GAUGE_MAX_VALUE - GAUGE_MIN_VALUE);
  29. }

  30. int main() {
  31.     // 1. 初始化摄像头(Titan Board 通常为 /dev/video0)
  32.     VideoCapture cap(0);
  33.     if (!cap.isOpened()) {
  34.         cerr << "无法打开摄像头!" << endl;
  35.         return -1;
  36.     }
  37.     // 降低分辨率,提升嵌入式性能
  38.     cap.set(CAP_PROP_FRAME_WIDTH, 640);
  39.     cap.set(CAP_PROP_FRAME_HEIGHT, 480);

  40.     Mat frame, gray, blur, edges, mask;
  41.     while (true) {
  42.         // 2. 读取帧并预处理
  43.         cap >> frame;
  44.         if (frame.empty()) break;

  45.         // 灰度化 + 高斯模糊(降噪)
  46.         cvtColor(frame, gray, COLOR_BGR2GRAY);
  47.         GaussianBlur(gray, blur, Size(5, 5), 1.5);

  48.         // 边缘检测(Canny)
  49.         Canny(blur, edges, 50, 150);

  50.         // 3. 检测表盘轮廓(圆形检测)
  51.         vector<Vec3f> circles;
  52.         HoughCircles(blur, circles, HOUGH_GRADIENT, 1,
  53.                      blur.rows/8, 100, 30, 100, 200);

  54.         if (!circles.empty()) {
  55.             // 取最大的圆形作为表盘(避免多轮廓干扰)
  56.             Vec3f largestCircle = circles[0];
  57.             Point center(largestCircle[0], largestCircle[1]);
  58.             int radius = largestCircle[2];

  59.             // 绘制表盘轮廓
  60.             circle(frame, center, radius, Scalar(0, 255, 0), 2);

  61.             // 4. 检测指针(基于掩码提取指针区域)
  62.             mask = Mat::zeros(gray.size(), CV_8UC1);
  63.             circle(mask, center, radius-5, Scalar(255), -1); // 表盘掩码
  64.             Mat masked_edges;
  65.             bitwise_and(edges, mask, masked_edges);

  66.             // 霍夫直线检测指针
  67.             vector<Vec4i> lines;
  68.             HoughLinesP(masked_edges, lines, 1, CV_PI/180, 50, 30, 10);

  69.             if (!lines.empty()) {
  70.                 // 取最接近圆心的直线作为指针
  71.                 Vec4i bestLine = lines[0];
  72.                 Point p1(bestLine[0], bestLine[1]);
  73.                 Point p2(bestLine[2], bestLine[3]);

  74.                 // 计算指针端点(延长线到表盘边缘)
  75.                 Point pointerEnd;
  76.                 float dx = p2.x - p1.x;
  77.                 float dy = p2.y - p1.y;
  78.                 float len = sqrt(dx*dx + dy*dy);
  79.                 if (len > 0) {
  80.                     pointerEnd.x = center.x + (dx/len) * radius;
  81.                     pointerEnd.y = center.y + (dy/len) * radius;
  82.                 }

  83.                 // 绘制指针
  84.                 line(frame, center, pointerEnd, Scalar(0, 0, 255), 2);

  85.                 // 5. 计算角度和数值
  86.                 float angle = calculateAngle(center, pointerEnd);
  87.                 float value = angleToValue(angle);

  88.                 // 显示结果
  89.                 putText(frame, "Value: " + to_string(value), Point(20, 40),
  90.                         FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 0), 2);
  91.             }
  92.         }

  93.         // 显示画面(Titan Board 需接显示屏,或注释改用串口输出)
  94.         imshow("Gauge Recognition", frame);

  95.         // 按ESC退出
  96.         if (waitKey(1) == 27) break;
  97.     }

  98.     cap.release();
  99.     destroyAllWindows();
  100.     return 0;
  101. }</span>
复制代码
  先拐个弯:测试RTT+LVGL 运行个demo
  1. /*
  2. * 前置条件:lv_conf.h中需启用以下字体(确保编译不优化掉)
  3. * #define LV_FONT_MONTSERRAT_20  1
  4. * #define LV_FONT_MONTSERRAT_24  1
  5. */
  6. static void lv_blessing_screen_create(void)
  7. {
  8.     lv_obj_t * scr = lv_screen_active();
  9.    
  10.     /* 1. 设置红色背景(与非网品牌红) */
  11.     lv_obj_set_style_bg_color(scr, lv_color_hex(0xC41E3A), LV_STATE_DEFAULT);
  12.     lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, LV_STATE_DEFAULT);
  13.     lv_obj_clear_flag(scr, LV_OBJ_FLAG_SCROLLABLE); // 禁止屏幕滚动
  14.    
  15.     /* 2. 第一行:Eefocus & Renesas*/
  16.     lv_obj_t * label1 = lv_label_create(scr);
  17.     lv_label_set_text(label1, "Eefocus & Renesas");
  18.     lv_obj_set_style_text_color(label1, lv_color_white(), LV_STATE_DEFAULT);
  19.     lv_obj_set_style_text_font(label1, &lv_font_montserrat_24, LV_STATE_DEFAULT);
  20.     lv_obj_align(label1, LV_ALIGN_TOP_MID, -120, 10);
  21.    
  22.     /* 3. 第二行:Wishes all electronic engineers -  */
  23.     lv_obj_t * label2 = lv_label_create(scr);
  24.     lv_label_set_text(label2, "Wishes all electronic engineers");
  25.     lv_obj_set_style_text_color(label2, lv_color_white(), LV_STATE_DEFAULT);
  26.     lv_obj_set_style_text_font(label2, &lv_font_montserrat_20, LV_STATE_DEFAULT);
  27.     lv_obj_align(label2, LV_ALIGN_CENTER, -120, -140);
  28.    
  29.     /* 4. 第三行:Success in the Year of the Horse! -  */
  30.     lv_obj_t * label3 = lv_label_create(scr);
  31.     lv_label_set_text(label3, "Success in the Year of the Horse!");
  32.     lv_obj_set_style_text_color(label3, lv_color_hex(0xFFD700), LV_STATE_DEFAULT);
  33.     lv_obj_set_style_text_font(label3, &lv_font_montserrat_20, LV_STATE_DEFAULT);
  34.     lv_obj_align(label3, LV_ALIGN_CENTER, -120, -80);
  35.    
  36.     /* 5. 第四行:Happy New Year - 核心修复(相对第三行对齐,100%显示) */
  37.     lv_obj_t * label4 = lv_label_create(scr);
  38.     lv_label_set_text(label4, "Happy New Year");
  39.     lv_obj_set_style_text_color(label4, lv_color_white(), LV_STATE_DEFAULT);
  40.     lv_obj_set_style_text_font(label4, &lv_font_montserrat_20, LV_STATE_DEFAULT);
  41.     // 关键改:基于第三行底部居中向下偏移80px,绕开屏幕底部边界问题
  42.     // X轴保留-120,和前三行水平对齐
  43.     lv_obj_align_to(label4, label3, LV_ALIGN_OUT_BOTTOM_MID, 0, 80);
  44. }
复制代码



  祝工程师项目马到功成!









分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /2 下一条