这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 开源硬件 » 【树莓派5】便携热成像仪

共6条 1/1 1 跳转至

【树莓派5】便携热成像仪

工程师
2026-03-26 18:09:39     打赏

【树莓派5】便携热成像仪

本文介绍了树莓派 5 单板计算机结合 SPI 通信协议驱动 LCD 彩色显示屏、结合 IIC 协议驱动 MLX90640 热成像传感器模块,实现便携热成像仪的项目设计。

项目介绍

项目包括驱动 LCD 彩屏、驱动 MLX90640 模块、综合搭建热成像仪三部分。

  • 硬件连接:使用杜邦线连接 LCD 彩屏、MLX90640 模块和树莓派;

  • 环境搭建:安装部署所需驱动、软件包和库;

  • 工程代码:流程图、关键代码;

  • 效果演示:LCD 显示彩色热成像图,终端打印温度范围。

硬件连接

包括 LCD 彩色显示屏、MLX90640模块和树莓派的接线方式。

LCD 彩屏


Raspberry PiLCDNote
GNDGNDGround
3.3VVinPower
Pin 22RSTReset
Pin 18DC/RSCommand
Pin 24CSChip Select
Pin 19MOSIData
Pin 23SCLKClock

详见:Python Wiring and Setup | LCD Display .

MLX90640 模块


MLX90640Raspberry PiNote
SDASDA (Pin3)Serial Data
SCLSCL (Pin5)Serial Clock
GNDGNDGround
VIN3V3Power

树莓派 40Pin 引脚定义: Raspberry Pi GPIO Pinout .

详见:MLX90640热成像传感器 - 立创开源硬件平台 .

环境搭建

创建并激活虚拟环境,安装所需 LCD 驱动包和 MLX90640 传感器驱动包

 python3 -m venv .venv
 source .venv/bin/activate
 pip install adafruit-circuitpython-rgb-display
 pip install adafruit-circuitpython-mlx90640

终端执行指令

sudo i2cdetect -y 1

显示 iic 设备地址为 0x33 对应设备为 MLX90640

i2c_33.jpg

流程图

flowchart_lcd_mlx90640.jpg

工程代码

终端执行指令 touch lcd_mlx90640_display.py 新建程序文件,并添加如下代码

 import time
 import board
 import busio
 import digitalio
 import numpy as np
 from PIL import Image, ImageDraw, ImageFont
 import adafruit_mlx90640
 from adafruit_rgb_display import st7735
 import matplotlib.cm as cm
 import matplotlib.colors as colors
 
 # LCD 引脚配置
 CS_PIN = digitalio.DigitalInOut(board.CE0)
 DC_PIN = digitalio.DigitalInOut(board.D24)
 RESET_PIN = digitalio.DigitalInOut(board.D25)
 BAUDRATE = 24000000
 
 # 传感器配置
 REFRESH_RATE = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ  # 4Hz 刷新率
 MIN_TEMP = 15.0  # 颜色映射的最小温度 (°C)
 MAX_TEMP = 35.0  # 颜色映射的最大温度 (°C)
 
 # 图像放大倍数 (传感器是 32x24,放大后更适合屏幕观看)
 SCALE_FACTOR = 8 
 
 # ===========================================
 
 def initialize_sensor():
     """初始化 MLX90640 传感器"""
     i2c = busio.I2C(board.SCL, board.SDA, frequency=1000000) # 提高 I2C 速度
     mlx = adafruit_mlx90640.MLX90640(i2c)
     mlx.refresh_rate = REFRESH_RATE
     # 读取一次以清除旧数据
     frame = [0] * 768
     try:
         mlx.getFrame(frame)
     except Exception as e:
         print(f"Warning: Initial read failed: {e}")
     return mlx
 
 def initialize_display():
     """初始化 LCD 屏幕"""
     spi = board.SPI()
     
     disp = st7735.ST7735R(
         spi, 
         rotation=90,  # 根据屏幕安装方向调整 (0, 90, 180, 270)
         cs=CS_PIN,
         dc=DC_PIN,
         rst=RESET_PIN,
         baudrate=BAUDRATE,
     )
     
     # 获取屏幕尺寸
     if disp.rotation % 180 == 90:
         width = disp.height
         height = disp.width
     else:
         width = disp.width
         height = disp.height
         
     return disp, width, height
 
 def create_color_lut(min_t, max_t, cmap_name='inferno'):
     """
     创建颜色查找表 (LUT)
     将温度范围映射到 0-255 的索引,再映射到 RGB 颜色
     """
     cmap = cm.get_cmap(cmap_name)
     norm = colors.Normalize(vmin=min_t, vmax=max_t)
     
     lut = []
     # 生成 256 个颜色的查找表
     for i in range(256):
         # 将 0-255 映射回温度范围用于归一化 (这里反向操作,直接生成归一化值)
         t_val = min_t + (max_t - min_t) * (i / 255.0)
         rgba = cmap(norm(t_val))
         # 转换为 0-255 的 RGB 整数
         r = int(rgba[0] * 255)
         g = int(rgba[1] * 255)
         b = int(rgba[2] * 255)
         lut.append((r, g, b))
     return lut
 
 def temperature_to_rgb(data_array, lut, min_t, max_t):
     """
     将温度矩阵转换为 RGB 图像数据。
     使用查找表加速转换。
     """
     # 限制数据在范围内,避免索引越界
     clipped_data = np.clip(data_array, min_t, max_t)
     
     # 归一化到 0-255 索引
     # (data - min) / (max - min) * 255
     range_t = max_t - min_t
     if range_t == 0: range_t = 0.001 # 防止除零
     indices = ((clipped_data - min_t) / range_t * 255).astype(int)
     
     # 映射 RGB
     h, w = indices.shape
     rgb_array = np.zeros((h, w, 3), dtype=np.uint8)
     
     # 应用 LUT (向量化操作,速度快)
     # 注意:lut 是列表,转为 numpy 数组以便索引
     lut_np = np.array(lut, dtype=np.uint8)
     rgb_array = lut_np[indices]
     
     return rgb_array
 
 def main():
     print("Initializing Sensor...")
     mlx = initialize_sensor()
     
     print("Initializing Display...")
     disp, screen_w, screen_h = initialize_display()
     
     # 创建颜色查找表
     print(f"Creating Color Map (Range: {MIN_TEMP}°C - {MAX_TEMP}°C)...")
     lut = create_color_lut(MIN_TEMP, MAX_TEMP, cmap_name='inferno')
     
     # 准备缓冲区
     frame = [0] * 768  # 32 * 24
     max_retries = 5
     
     # 用于显示统计信息的字体
     try:
         font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 10)
     except IOError:
         font = ImageFont.load_default()
 
     print("Starting Thermal Loop...")
     start_time = time.time()
     frame_count = 0
 
     while True:
         t1 = time.monotonic()
         retry_count = 0
         success = False
         
         # 读取传感器数据
         while retry_count < max_retries:
             try:
                 mlx.getFrame(frame)
                 success = True
                 break
             except ValueError:
                 retry_count += 1
             except RuntimeError as e:
                 retry_count += 1
                 if retry_count >= max_retries:
                     print(f"Sensor Error after {max_retries} retries: {e}")
                     break
             time.sleep(0.01) # 短暂等待后重试
 
         if not success:
             continue
 
         # 数据处理
         data_array = np.reshape(frame, (24, 32))
         # MLX90640 
         data_array = np.fliplr(data_array)
 
         # 动态调整温度范围 (颜色随环境自动变化,取消下面两行注释,并注释固定的 MIN/MAX)
         # curr_min = np.min(data_array)
         # curr_max = np.max(data_array)
         # 为了防止噪声导致颜色闪烁,通常建议设置一个固定的范围或使用平滑滤波
         
         # 转换为 RGB 图像 (24x32)
         rgb_small = temperature_to_rgb(data_array, lut, MIN_TEMP, MAX_TEMP)
         
         # 将 numpy 数组转换为 PIL Image
         img_small = Image.fromarray(rgb_small, mode='RGB')
         
         # 放大图像以适应屏幕 (使用双线性插值)
         target_w = 32 * SCALE_FACTOR
         target_h = 24 * SCALE_FACTOR
         img_large = img_small.resize((target_w, target_h), Image.BILINEAR)
         
         # 创建一个与屏幕大小相同的黑色背景
         image = Image.new("RGB", (screen_w, screen_h), (0, 0, 0))
         
         # 计算居中位置
         paste_x = (screen_w - target_w) // 2
         paste_y = (screen_h - target_h) // 2
         
         # 将热成像图粘贴到背景上
         image.paste(img_large, (paste_x, paste_y))
         
         # 绘制文字信息 (温度统计)
         draw = ImageDraw.Draw(image)
         current_min = np.min(data_array)
         current_max = np.max(data_array)
         current_avg = np.mean(data_array)
         
         info_text = f"Min: {current_min:.1f}C\nMax: {current_max:.1f}C\nAvg: {current_avg:.1f}C"
         # 在左上角绘制文字 (白色)
         draw.text((5, 5), info_text, fill=(255, 255, 255), font=font)
         
         # 显示 FPS
         fps = 1.0 / (time.monotonic() - t1) if (time.monotonic() - t1) > 0 else 0
         fps_text = f"FPS: {fps:.1f}"
         draw.text((5, screen_h - 15), fps_text, fill=(255, 255, 0), font=font)
 
         # 更新屏幕
         disp.image(image)
         
         # 简单的帧率控制与统计
         frame_count += 1
         if frame_count % 10 == 0:
             elapsed = time.time() - start_time
             if elapsed > 0:
                 print(f"Running... Avg FPS: {frame_count/elapsed:.2f}, Temp Range: {current_min:.1f}-{current_max:.1f}")
 
 if __name__ == '__main__':
     try:
         main()
     except KeyboardInterrupt:
         print("\nExiting...")

保存代码。

效果演示

  • 终端执行指令 python lcd_mlx90640_display.py 运行程序;

  • LCD 显示实时热成像图;

lcd_mlx90640.jpg

  • 同时终端打印热成像温度范围

  • lcd_mlx90640_print.jpg

总结

本文介绍了树莓派 5 单板计算机结合 SPI 通信协议驱动 LCD 彩色显示屏、结合 IIC 协议驱动 MLX90640 热成像传感器模块,实现便携热成像仪的项目设计,为相关产品在工业物联网领域的快速开发和应用设计提供了参考。







关键词: 树莓派     传感器     驱动     显示屏     模块    

专家
2026-03-27 08:14:01     打赏
2楼

谢谢楼主分享


高工
2026-03-28 23:04:42     打赏
3楼

看图片,感觉热成像的效果不算特别好,图片下面那几层,很明显的像是临界时的马赛克的感觉,有办法优化不?


高工
2026-03-30 12:07:17     打赏
4楼

图像有加强呀,看起来效果挺好的。


专家
2026-03-31 15:03:00     打赏
5楼

帖子很好!程序代码、处理流程都贴上来了,方便分享、学习!谢谢!


高工
2026-04-01 08:31:50     打赏
6楼

谢谢分享!!


共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]