手持红外热成像仪V2.0-TinyML嵌入轻量级神经网络(on going)

2.4k 词

在之前的基础上改进了一部分

硬件上把串口和SWD下载口引出来了,夹具下载有点不稳定

同时把手头上的LCD模组和红外传感器模组给用了,没有额外购买物资,成品图如下:

左边是V1,右边是V2

 

软件部分增加了一些图像处理的功能:

图像平滑:

双线性插值

void interpolateTemperature(float *src, float *dst, uint8_t src_w, uint8_t src_h, uint8_t dst_w, uint8_t dst_h) {
    float x_ratio = (float)(src_w-1) / dst_w;
    float y_ratio = (float)(src_h-1) / dst_h;
    for (int y = 0; y < dst_h; y++) {
        for (int x = 0; x < dst_w; x++) {
            float x_src = x * x_ratio;
            float y_src = y * y_ratio;
            int x0 = (int)x_src, y0 = (int)y_src;
            float x_diff = x_src - x0;
            float y_diff = y_src - y0;
            
            float val = src[y0*src_w + x0] * (1-x_diff)*(1-y_diff)
                      + src[y0*src_w + x0+1] * x_diff*(1-y_diff)
                      + src[(y0+1)*src_w + x0] * (1-x_diff)*y_diff
                      + src[(y0+1)*src_w + x0+1] * x_diff*y_diff;
            dst[y*dst_w + x] = val;
        }
    }
}

最近邻插值

void nearestNeighborInterpolate(float *src, float *dst, uint8_t src_w, uint8_t src_h, uint8_t dst_w, uint8_t dst_h) {
    float x_ratio = (float)src_w / dst_w;
    float y_ratio = (float)src_h / dst_h;
    
    for (int y = 0; y < dst_h; y++) {
        for (int x = 0; x < dst_w; x++) {
            int src_x = (int)(x * x_ratio);
            int src_y = (int)(y * y_ratio);            
            // 防止越界
            if (src_x >= src_w) src_x = src_w - 1;
            if (src_y >= src_h) src_y = src_h - 1;
            
            dst[y * dst_w + x] = src[src_y * src_w + src_x];
        }
    }
}

边缘提取

// Sobel 算子卷积核
const int sobel_x[3][3] = {
    {-1, 0, 1},
    {-2, 0, 2},
    {-1, 0, 1}
};

const int sobel_y[3][3] = {
    {-1, -2, -1},
    { 0,  0,  0},
    { 1,  2,  1}
};


void detectEdges(float *input, uint8_t *output, uint8_t width, uint8_t height) {
    for (int y = 1; y < height - 1; y++) {       
        for (int x = 1; x < width - 1; x++) {
            float gx = 0, gy = 0;          
            // 3x3 邻域卷积
            for (int j = -1; j <= 1; j++) {
                for (int i = -1; i <= 1; i++) {
                    float pixel = input[(y + j) * width + (x + i)];
                    gx += pixel * sobel_x[j + 1][i + 1];
                    gy += pixel * sobel_y[j + 1][i + 1];
                }
            }
            uint8_t edge_strength = (uint8_t)(fabs(gx) + fabs(gy));
            edge_strength = (edge_strength > 255) ? 255 : edge_strength;
            output[y * width + x] = edge_strength;
        }
    }
}


static void drawPicture3(void) {
    uint8_t cell_size = 4;
    uint8_t start_x = 0;
    uint8_t start_y = 16;
    
    float interpolated_temp[32 * 24];  
    uint8_t edge_map[32 * 24];         
    
    //双线性插值
    interpolateTemperature(tempValues, interpolated_temp, 32, 24, 32, 24);
    //边缘检测
    detectEdges(interpolated_temp, edge_map, 32, 24);  
    //只绘制边缘(白色),其余区域黑色
    for (int y = 0; y < 24; y++) {
        for (int x = 0; x < 32; x++) {
            uint16_t color = ST7735_BLACK;  // 默认黑色
            // 如果边缘强度足够高,则显示白色
            if ((edge_map[y * 32 + x] > 10  ) && (edge_map[y * 32 + x] < 40  )){  // 阈值可调
                color = ST7735_WHITE;
            }
            ST7735_FillRectangle(
                start_x + x * cell_size,
                start_y + (23 - y) * cell_size,
                cell_size,
                cell_size,
                color
            );
        }
    }
}

图像识别

准备往设备里嵌一个轻量级的神经网络