当前位置: 华文世界 > 手机

一块免费的PCB,就能让手机秒变热成像仪!方法很简单

2023-12-08手机

一块小小的免费PCB,就能 让手机秒变热成像仪

还是贼拉 高清 的那种!

总开发成本也就100元左右!

这不得围观一下!

一、开源描述

抛开了传统的热成像仪制作方式,使用 可见光camera 热成像传感器 制作了一个 双目手机热成像仪 。像素:640x480。

目前,项目已全开源。

——这个热成像仪的 设计原理 是什么? 电路 如何设计? 软件 如何设计?使用了什么算法和技巧?

下面一一进行分析!

二、项目功能实现原理

了解功能原理前须知:

热成像仪,为什么要设计成「双目」的?

  • 可见光相机具有分辨率高、帧率高的特点。
  • 热成像传感器可以测量温度分布,但是分辨率低、帧率低。
  • 使用可见光图像来补偿热成像图像,就可以达到热成像图—— 质量高、分辨率高 的效果。

    那具体的功能实现是怎样的?下面就分析一下!

    本项目整体功能框架图如下。

    首先MCU通过I2C接口 读取热成像传感器 数据,通过USB接口 传向USB Hub

    Camera 通用免驱USB摄像头,也 接到USB Hub上面

    然后将Usb Hub和Android手机连接。

    接着,Android手机的应用层就会获取到两个传感器的数据。

    通过一定算法进行融合,就能得到——分辨率较高、质量较好的热成像图!

    这是 热水壶 热量分布图:

    这是 白天公园 的热量分布图:

    这是 夜间街道 的热量分布图:

    想实现这样的效果,软硬件该如何设计呢?

    三、硬件设计原理

    原理图

    PCB图

    本章会将原理图拆分为5部分,一一说明一下。

    1.MCU

    MCU使用的是STM32F411CEU6,带USB FS,其带浮点运算单元可对热成像数据进行解算。

    2.USB Hub

    USB Hub使用的是SL2.1A,支持USB HS,可以用于传输摄像头数据。此处接了晶振,可不焊接。

    Camera则通过焊接方式连接到CAM_DM/CAM_DP。

    USB1是一个USB TypeC公头,用于连接手机。

    3.热成像传感器

    热成像传感器使用的是MLX90640。

  • 分辨率:32x24像素;
  • I2C接口最高速率:1MHz。
  • 4.电源

    电源这里直接使用了一块LDO进行稳压,型号是ME6211。

    可以 直接用低ESR的陶瓷电容 进行输入输出的稳压

    5.其他

    电源灯和测试LED电路:


    调试SWD接口:


    测试点,固件使用UART2作为Debug串口:

    完成了硬件部分的设计,咱们再深入剖析一下,软件部分的核心算法是什么!

    四、软件设计原理

    软件部分,将重点分析——软件设计思路、Android APP设计、数据融合算法,这三个部分。

    1.软件设计思路

    开发环境使用STM32CubeIDE。

    软件整体设计框架图如下:

    通过I2C从mlx90640读取数据,进行打包,再使用USB发送读取到的数据。

    整个过程使用一个循环即可。

    其中mlx90640的 温度测量范围是 -40到300摄氏度

    值得注意的是:

    温度测量范围需要保留两位小数,转换为整型为-4000到30000,也可以用16位整型覆盖,使用一个0x8000为起始码,后续跟768个温度数据。

    mlx90640官方已经提供驱动, 只需要实现对应I2C的读写操作 ,即可通过API来读取传感器数据。

    USB库由CubeIDE自动生成 ,直接调用USBCDC发送数据即可。

    2.Android APP

    Android端主要负责——数据读取、融合和显示功能的实现。

    这里有两个USB设备:

  • 一个是USB串口,用于传输热成像数据;
  • 一个是USB摄像头,用于传输图像数据。
  • ①软件框架

    Camera和热成像传感器的数据读取都有对应的库支持。

    由于两个库对数据的读取都是用的异步回调的方式,因此这里采用双buffer缓存的机制

    就以Camera为例,解析一下数据读取的逻辑:

    初始化一个长度为2的队列 。回调发生时,就新申请一块buffer,然后将YUV数据拷贝到这块buffer中,再将这块buffer放入队列。

    起一个线程 ,不断从队列中读取数据,用于数据融合。

    如果线程读取太慢 ,回调发现队列已经满,则从队列中取出一块buffer丢弃,然后再将新的buffer放入队列。

    如果回调一直不来 ,线程队列为空,则跳过下一次再读取。因为每一次回调都会新申请一块buffer,因此buffer不存在并发问题。

    队列添加和删除 访问的都是同一个数据结构,存在并发问题, 操作时需要注意上锁

    如上所述,Camera有两个队列:

  • 一个存放YUV数据;
  • 一个存放热成像数据。
  • 只通过一个线程来访问两个队列。两个队列都有数据时才取出,并进行数据融合。

    由此我们得出,软件总体运行流程如下:

    ②Camera数据读取和预览

    Android对摄像头的支持使用 UVCAndroid

    该库基于saki4510t/UVCCamera开发,提供了更为简单的接口。

    ③热成像数据读取和预览

    热成像数据通过USBCDC传输,在Android端看到的是一个虚拟串口。

    Android开发环境中,主要使用 felHR85/UsbSerial 提供虚拟串口的操作支持,并在回调中将热成像数据放入队列中。

    3.数据融合

    上面提到过多次「数据融合」。

    那么,要如何获取数据,并进行融合呢?

    ①获取数据

    使用一个线程即可获取数据。

    这里预计可见光相机的帧率会比热成像帧率更高。

    因此在等待mYUVQueue队列有数据时才会进行数据融合。

    当 mThermalQueue 没有数据时,则默认使用上一帧的数据。

    ②融合算法

    这里摄像头采集的是可见光的图像,分辨率是640x480;

    热成像采集的是温度分布,分辨率是32x24。

    融合算法的目的是 ——通过参考可见光的图像, 让热成像采集的温度图像 分辨率更高, 拥有更多的细节

    该算法基于一个假设: 颜色相近的像素,大概率来自同一个物体,对应的温度也应该相近。

    该算法的流程如下:

    将热成像温度的分布,通过线性插值扩大到640x480像素。

    以当前像素点为中心,选定一个长宽为REF_LEN的方形区域。

  • 假设当前camera像素的亮度值为v;
  • 方形区域中每个camera像素的亮度值为v_i;
  • 每个thermal像素的亮度值为t_i。
  • 计算当前像素和参考区域每个像素的差值delta_v_i。
  • 计算系数矩阵,系数表示每个像素的权重。

  • 当delta_v_i >= 0时,k_i = 1 - delta_v_i / 255;
  • 当delta_v_i < 0时,k_i = 1 + delta_v_i / 255。
  • 计算估计值矩阵,表示每个像素相对于当前像素温度的估计值,t_hat_i = k_i * t_i。

    计算估计值矩阵的平均值,即当前像素的温度估计值。

    由以上算法可知,在参考值矩阵中,与当前像素值 色度差值越小 ,对应的 系数k_i也就越大 ,对应 温度的估计值也就越大 ,对应的估计的 温度也就越接近

    举个栗子。

    使用如下两个图片进行本地仿真。

    第一张 camera拍的 图片, 第二张 热成像获取的 经过插值放大后的温度分布图片。分辨率均为640x480。

    当REF_LEN = 4时,融合结果如下:


    当REF_LEN = 7时,融合结果如下:

    可见, 加入融合算法之后 ,原本插值放大的低频信息中, 多出了一些高频细节

    色彩映射

    完成一个热成像仪的最后一步,就是将融合后的图像转为伪彩色,再按照YUV的方式映射到camera图像中。

    最终效果如下:

    因为色彩映射的原因,原本热成像融合出的高频细节被淹没在海量的camera图像细节中,因此图像融合算法的效果并不明显,后续可能会分为两种模式分别进行输出。

    参考资料:

    [1]https://oshwhub.com/colourfate/binocular_thermal_imager

    — 完 —

    嘉立创EDA·头条号

    关注我,看一手优质开源项目