1. 引言

随着无人机技术的普及,建筑结构检测逐渐从人工巡检转向自动化、智能化。然而,实时图像处理往往需要高性能硬件,限制了其在低成本嵌入式平台上的应用。本文旨在探索在资源受限的STM32微控制器上实现轻量级结构缺陷检测的可能性。

我们设计了一个仿真系统,模拟无人机下视摄像头采集灰度图像,通过一系列经典图像处理算法提取裂缝特征,并通过UART将指标上报。系统基于RT-Thread实时操作系统,利用多线程管理图像采集、处理和通信任务,确保实时性。

2. 系统概述

2.1 功能目标

  • 模拟生成带裂缝的32×32灰度图像(每帧)。

  • 对图像进行预处理、边缘检测、二值化和形态学修复。

  • 识别裂缝连通域,计算5项关键指标:

    • 裂缝数量(连通域个数)

    • 裂缝总面积(像素)

    • 裂缝总长度(像素,由周长近似)

    • 最大裂缝长度(像素)

    • 平均裂缝宽度(面积/长度*2)

  • 将指标通过UART以自定义二进制协议发送至上位机。

  • 使用RT-Thread多线程管理,每2秒处理一帧图像。

2.2 硬件平台

  • MCU:STM32F407ZGT6(Cortex-M4,168MHz)

  • UART:UART2(PA9 TX,PA10 RX),波特率115200

  • 资源占用:Flash 62.98KB,RAM 6.06KB(编译结果)

2.3 软件平台

  • 操作系统:RT-Thread 4.1.0

  • 开发环境:RT-Thread Studio / Keil MDK

  • 工具链:arm-none-eabi-gcc

3. 系统架构

系统采用生产者-消费者模型,包含两个线程和一个邮箱:

  • 采集线程:负责生成测试图像(模拟摄像头数据),将图像数据通过动态内存分配放入邮箱。

  • 处理线程:从邮箱获取图像数据,执行图像处理算法,提取裂缝指标,并通过UART发送。

  • 邮箱:用于线程间通信,容量为5个图像指针,避免数据覆盖。

4. 图像处理算法详解

本节详细说明处理流程中的每个步骤,并给出核心代码片段。

4.1 图像生成

为模拟真实场景,我们在灰色背景(灰度200)上绘制了多条裂缝:水平线、垂直线、斜线和斑点区域。代码如下:

static void generate_test_image(void)
{
    for (int y = 0; y < IMG_HEIGHT; y++)
        for (int x = 0; x < IMG_WIDTH; x++)
            img_data[y][x] = 200;
    // 裂缝1:水平线
    for (int i = 5; i < 10; i++) img_data[8][i] = 30;
    // 裂缝2:垂直线
    for (int i = 12; i < 18; i++) img_data[i][20] = 40;
    // 裂缝3:斜线
    for (int i = 0; i < 8; i++) img_data[20 + i][5 + i] = 25;
    // 裂缝4:斑点
    for (int y = 25; y < 30; y++)
        for (int x = 25; x < 30; x++)
            img_data[y][x] = 50;
}

4.2 高斯滤波

使用3×3高斯核对图像进行平滑,消除噪声。核系数为:

1 2 1
2 4 2
1 2 1

除以16归一化。代码实现了边界复制处理。

4.3 Sobel边缘检测

计算水平和垂直梯度,用绝对值之和近似梯度幅值。公式:

Gx = (P3 + 2P6 + P9) - (P1 + 2P4 + P7)
Gy = (P7 + 2P8 + P9) - (P1 + 2P2 + P3)
Mag = |Gx| + |Gy|

4.4 阈值分割

设定阈值为50,将边缘图像二值化:

dst[y][x] = (src[y][x] > thresh) ? 255 : 0;

4.5 形态学闭运算

闭运算(先膨胀后腐蚀)用于连接断裂的裂缝边缘,填充小孔。采用3×3结构元素。

4.6 连通域分析

实现8邻域连通域标记算法(两遍扫描),并记录每个连通域的面积和周长(边界像素数)。最后计算全局指标:

  • 裂缝数量 = 连通域个数

  • 总面积 = 各连通域面积之和

  • 总长度 = 各连通域周长之和(近似裂缝总长度)

  • 最大长度 = 最大连通域周长

  • 平均宽度 = 总面积 × 2 / 总长度(经验公式)

5. 数据通信协议

为了可靠传输,设计了二进制帧格式:

字节偏移 内容 长度 说明
0 帧头 1 0xAA
1 命令字 1 0x02(裂缝数据)
2-3 数据长度 2 后面数据区长度(固定为12)
4-15 数据区 12 CrackMetrics结构体(见下文)
16 校验和 1 从命令字到数据区的累加和
17 帧尾 1 0x55

CrackMetrics结构体(12字节):

typedef struct {
    uint32_t timestamp;   // 4字节
    uint16_t crack_count; // 2字节
    uint16_t total_area;  // 2字节
    uint16_t total_length;// 2字节
    uint16_t max_length;  // 2字节
    uint8_t  avg_width;   // 1字节
} CrackMetrics;

发送函数计算校验和后通过UART设备写入:

static void send_crack_metrics(const CrackMetrics* metrics)
{
    ProtocolFrame frame;
    frame.header = FRAME_HEADER;
    frame.cmd = CMD_CRACK_DATA;
    frame.data_len = sizeof(CrackMetrics);
    frame.metrics = *metrics;
    uint8_t* p = (uint8_t*)&frame.cmd;
    frame.checksum = calc_checksum(p, sizeof(frame.cmd) + sizeof(frame.data_len) + sizeof(CrackMetrics));
    frame.tail = FRAME_TAIL;
    rt_device_write(uart_dev, 0, &frame, sizeof(frame));
}

6. 多线程设计与RT-Thread实现

6.1 线程创建

在应用初始化函数中,创建两个线程和一个邮箱:

static int inspection_app_init(void)
{
    uart_init();
    img_mailbox = rt_mb_create("img_mb", 5, RT_IPC_FLAG_FIFO);
    rt_thread_create("capture", capture_thread_entry, ...);
    rt_thread_create("process", process_thread_entry, ...);
    return 0;
}
INIT_APP_EXPORT(inspection_app_init);

6.2 采集线程

循环生成图像,分配内存,发送邮箱指针:

static void capture_thread_entry(void* parameter)
{
    while (1) {
        generate_test_image();
        uint8_t* img_ptr = rt_malloc(IMG_SIZE);
        memcpy(img_ptr, img_data, IMG_SIZE);
        rt_mb_send(img_mailbox, (rt_uint32_t)img_ptr);
        rt_thread_mdelay(2000);
    }
}

6.3 处理线程

等待邮箱消息,处理图像并释放内存:

static void process_thread_entry(void* parameter)
{
    while (1) {
        rt_mb_recv(img_mailbox, &img_ptr, RT_WAITING_FOREVER);
        // 处理图像...
        rt_free(img);
    }
}

7. 实验结果

7.1 编译资源占用

使用arm-none-eabi-gcc编译,结果如下:

text    data    bss     dec     hex
62616   1880    4328    68824   10cd8
Flash: 64496 B (62.98 KB)
RAM:   6208 B (6.06 KB)

可见系统可在仅63KB Flash、6KB RAM的MCU上运行,非常适合低成本嵌入式应用。

7.2 串口输出

处理线程每2秒打印一次指标,同时通过UART发送二进制帧。串口助手接收到的数据示例(十六进制):

AA 02 00 0C 00 00 00 01 00 13 00 1A 00 12 00 0F 03 55

解析:

  • 帧头:AA

  • 命令:02

  • 数据长度:00 0C (12)

  • 时间戳:00 00 00 01 (1秒)

  • 裂缝数量:00 13 (19)

  • 总面积:00 1A (26)

  • 总长度:00 12 (18)

  • 最大长度:00 0F (15)

  • 平均宽度:03 (3)

  • 校验和:? (示例中省略计算)

  • 帧尾:55

控制台输出:

Metrics: cnt=19, area=26, tlen=18, maxlen=15, avgw=3

7.3 性能分析

每帧图像处理时间约数毫秒(MCU主频168MHz),满足2秒间隔的实时性要求。

8. 项目总结与展望

本文成功实现了一个基于RT-Thread的无人机结构检测嵌入式仿真系统,证明了在资源有限的MCU上运行完整图像处理链的可行性。系统具有以下特点:

  • 模块化设计:采集、处理、通信分离,便于移植和扩展。

  • 算法轻量级:采用经典图像处理算法,无需深度学习库,适合嵌入式环境。

  • 资源高效:仅占用63KB Flash和6KB RAM,可运行于STM32F103等中低端芯片。

  • 协议通用:自定义二进制协议可适配各种上位机。

未来工作方向:

  1. 接入真实摄像头:通过DCMI或SPI接口采集真实图像,替换模拟数据。

  2. 算法优化:引入更复杂的特征提取(如LBP、HOG),提升检测精度。

  3. 多传感器融合:结合IMU数据修正图像畸变,提高定位精度。

  4. 无线传输:将UART改为WiFi/4G模块,实现远程数据上报。


作者:佳木逢钺
日期:2025年3月8日
版权声明:本文为CSDN博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐