【瑞萨AI挑战赛】 部署仪表识别算法方案(一)
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组件实现:
核心算法:
<span style="color: rgb(0, 0, 0); font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; white-space: pre;">#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cmath>
#include <iostream>
using namespace cv;
using namespace std;
// 仪表参数配置(根据实际仪表调整)
const float GAUGE_MIN_ANGLE = 45.0f; // 指针最小值对应角度(顺时针)
const float GAUGE_MAX_ANGLE = 315.0f; // 指针最大值对应角度
const float GAUGE_MIN_VALUE = 0.0f; // 仪表最小值
const float GAUGE_MAX_VALUE = 100.0f;// 仪表最大值
const int GAUGE_RADIUS = 150; // 表盘半径(像素)
// 计算两点间角度
float calculateAngle(Point center, Point point) {
float dx = point.x - center.x;
float dy = point.y - center.y;
float angle = atan2(dy, dx) * 180.0f / CV_PI;
if (angle < 0) angle += 360.0f;
return angle;
}
// 角度转仪表数值
float angleToValue(float angle) {
// 角度范围映射到数值范围
if (angle < GAUGE_MIN_ANGLE) angle += 360.0f;
if (angle > GAUGE_MAX_ANGLE) angle = GAUGE_MAX_ANGLE;
float ratio = (angle - GAUGE_MIN_ANGLE) / (GAUGE_MAX_ANGLE - GAUGE_MIN_ANGLE);
return GAUGE_MIN_VALUE + ratio * (GAUGE_MAX_VALUE - GAUGE_MIN_VALUE);
}
int main() {
// 1. 初始化摄像头(Titan Board 通常为 /dev/video0)
VideoCapture cap(0);
if (!cap.isOpened()) {
cerr << "无法打开摄像头!" << endl;
return -1;
}
// 降低分辨率,提升嵌入式性能
cap.set(CAP_PROP_FRAME_WIDTH, 640);
cap.set(CAP_PROP_FRAME_HEIGHT, 480);
Mat frame, gray, blur, edges, mask;
while (true) {
// 2. 读取帧并预处理
cap >> frame;
if (frame.empty()) break;
// 灰度化 + 高斯模糊(降噪)
cvtColor(frame, gray, COLOR_BGR2GRAY);
GaussianBlur(gray, blur, Size(5, 5), 1.5);
// 边缘检测(Canny)
Canny(blur, edges, 50, 150);
// 3. 检测表盘轮廓(圆形检测)
vector<Vec3f> circles;
HoughCircles(blur, circles, HOUGH_GRADIENT, 1,
blur.rows/8, 100, 30, 100, 200);
if (!circles.empty()) {
// 取最大的圆形作为表盘(避免多轮廓干扰)
Vec3f largestCircle = circles;
Point center(largestCircle, largestCircle);
int radius = largestCircle;
// 绘制表盘轮廓
circle(frame, center, radius, Scalar(0, 255, 0), 2);
// 4. 检测指针(基于掩码提取指针区域)
mask = Mat::zeros(gray.size(), CV_8UC1);
circle(mask, center, radius-5, Scalar(255), -1); // 表盘掩码
Mat masked_edges;
bitwise_and(edges, mask, masked_edges);
// 霍夫直线检测指针
vector<Vec4i> lines;
HoughLinesP(masked_edges, lines, 1, CV_PI/180, 50, 30, 10);
if (!lines.empty()) {
// 取最接近圆心的直线作为指针
Vec4i bestLine = lines;
Point p1(bestLine, bestLine);
Point p2(bestLine, bestLine);
// 计算指针端点(延长线到表盘边缘)
Point pointerEnd;
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
float len = sqrt(dx*dx + dy*dy);
if (len > 0) {
pointerEnd.x = center.x + (dx/len) * radius;
pointerEnd.y = center.y + (dy/len) * radius;
}
// 绘制指针
line(frame, center, pointerEnd, Scalar(0, 0, 255), 2);
// 5. 计算角度和数值
float angle = calculateAngle(center, pointerEnd);
float value = angleToValue(angle);
// 显示结果
putText(frame, "Value: " + to_string(value), Point(20, 40),
FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 0), 2);
}
}
// 显示画面(Titan Board 需接显示屏,或注释改用串口输出)
imshow("Gauge Recognition", frame);
// 按ESC退出
if (waitKey(1) == 27) break;
}
cap.release();
destroyAllWindows();
return 0;
}</span> 先拐个弯:测试RTT+LVGL 运行个demo
/*
* 前置条件:lv_conf.h中需启用以下字体(确保编译不优化掉)
* #define LV_FONT_MONTSERRAT_201
* #define LV_FONT_MONTSERRAT_241
*/
static void lv_blessing_screen_create(void)
{
lv_obj_t * scr = lv_screen_active();
/* 1. 设置红色背景(与非网品牌红) */
lv_obj_set_style_bg_color(scr, lv_color_hex(0xC41E3A), LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, LV_STATE_DEFAULT);
lv_obj_clear_flag(scr, LV_OBJ_FLAG_SCROLLABLE); // 禁止屏幕滚动
/* 2. 第一行:Eefocus & Renesas*/
lv_obj_t * label1 = lv_label_create(scr);
lv_label_set_text(label1, "Eefocus & Renesas");
lv_obj_set_style_text_color(label1, lv_color_white(), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(label1, &lv_font_montserrat_24, LV_STATE_DEFAULT);
lv_obj_align(label1, LV_ALIGN_TOP_MID, -120, 10);
/* 3. 第二行:Wishes all electronic engineers -*/
lv_obj_t * label2 = lv_label_create(scr);
lv_label_set_text(label2, "Wishes all electronic engineers");
lv_obj_set_style_text_color(label2, lv_color_white(), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(label2, &lv_font_montserrat_20, LV_STATE_DEFAULT);
lv_obj_align(label2, LV_ALIGN_CENTER, -120, -140);
/* 4. 第三行:Success in the Year of the Horse! -*/
lv_obj_t * label3 = lv_label_create(scr);
lv_label_set_text(label3, "Success in the Year of the Horse!");
lv_obj_set_style_text_color(label3, lv_color_hex(0xFFD700), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(label3, &lv_font_montserrat_20, LV_STATE_DEFAULT);
lv_obj_align(label3, LV_ALIGN_CENTER, -120, -80);
/* 5. 第四行:Happy New Year - 核心修复(相对第三行对齐,100%显示) */
lv_obj_t * label4 = lv_label_create(scr);
lv_label_set_text(label4, "Happy New Year");
lv_obj_set_style_text_color(label4, lv_color_white(), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(label4, &lv_font_montserrat_20, LV_STATE_DEFAULT);
// 关键改:基于第三行底部居中向下偏移80px,绕开屏幕底部边界问题
// X轴保留-120,和前三行水平对齐
lv_obj_align_to(label4, label3, LV_ALIGN_OUT_BOTTOM_MID, 0, 80);
}
祝工程师项目马到功成!
页:
[1]