Skip to content

使用ESP32s3采集红外图像并显示,且将数据上传到上位机,基于PlatformIO开发

Notifications You must be signed in to change notification settings

silencer-z/ESP32-IR

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PIO IR

开发环境

  • 开发板:lilygo-t-display-s3
  • 开发框架:platformIO-arduino
  • 其他组件:MLX90640 24x32 红外摄像头

功能

  • 红外图像采集:使用Adafruit的驱动库完成对红外图像的采集
  • 红外图像显示:采集完成的数据,将会被插值后使用假彩色显示在屏幕上,屏幕的驱动库依赖于TFT-eSPI库
  • 数据串口传输:采集完成的原始数据也会从串口发送出去,每次发送一帧的数据

串口接收代码参考

主要完成:1.接收数据;2.显示假彩色图像;3.显示最高最低温度;4.保存一帧数据

import numpy as np
import serial
import csv,time,os
import cv2

def read_ir_data(port='/dev/ttyACM0', baud_rate=115200, output_dir='saved_images'):
    """
    从串口读取一帧温度数据。
    每帧数据为一行文本(以换行符结尾),其中包含768个用逗号分隔的浮点数。
    显示伪彩色图像,并在按下 's' 键时保存图像,按 'q' 键退出。
    """
    # 如果保存目录不存在,则创建
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    ser = None

    # 持续尝试打开串口设备,直到成功连接
    print(f"正在尝试从 {port} 连接设备...", end="")
    while ser is None:
        try:
            ser = serial.Serial(port, baud_rate, timeout=1)
            print(f"\nConnected to {port} at {baud_rate} baud")
        except serial.SerialException as e:
            print(".", end="")
            time.sleep(1)

    print(f"[INFO] 开始接收数据,按 'q' 退出,按 's' 保存伪彩色图像")
    cv2.namedWindow("MLX90640 Video", cv2.WINDOW_NORMAL)
    img_count = 0

    try:
        while True:
            # 读取一行数据
            try:
                line = ser.readline().decode().strip()
            except UnicodeDecodeError:
                continue

            if not line:
                continue

            parts = line.split(',')
            if len(parts) != 768:
                continue

            try:
                values = [float(x) for x in parts]
            except ValueError:
                continue

            # 转换为 2D 数组、归一化,并生成伪彩色图像
            frame = np.array(values).reshape((24, 32))
            # 计算当前帧的最小温度和最大温度
            min_temp_val = np.min(frame)
            max_temp_val = np.max(frame)
            norm_frame = np.clip((frame - min_temp_val) / (max_temp_val - min_temp_val), 0, 1)
            norm_frame = (norm_frame * 255).astype(np.uint8)
            color_frame = cv2.applyColorMap(norm_frame, cv2.COLORMAP_JET)
            display_img = cv2.resize(color_frame, (320, 240), interpolation=cv2.INTER_CUBIC)

            # 生成左侧伪彩色对照条,采用与归一化同一映射
            bar_width = 50
            bar_height = display_img.shape[0]  # 与显示图像同高
            # 生成垂直梯度,从上到下由 255 到 0
            gradient = np.linspace(255, 0, bar_height, dtype=np.uint8)
            gradient = np.tile(gradient.reshape(bar_height, 1), (1, bar_width))
            color_bar = cv2.applyColorMap(gradient, cv2.COLORMAP_JET)

            # 构造合成图像:左侧为对照条,右侧为显示图像,上部分整体高度与显示图像一致,下方为标注区域
            text_height = 30
            final_width = bar_width + display_img.shape[1]
            final_height = display_img.shape[0] + text_height
            final_img = np.zeros((final_height, final_width, 3), dtype=np.uint8)

            # 将伪彩色对照条放在合成图像左侧
            final_img[:bar_height, :bar_width] = color_bar
            # 将显示图像放在对照条右侧
            final_img[:bar_height, bar_width:final_width] = display_img

            # 在合成图像的底部标注最小温度和最大温度
            label = f"Min: {min_temp_val:.2f} C    Max: {max_temp_val:.2f} C"
            # 设置字体、大小及厚度
            font = cv2.FONT_HERSHEY_SIMPLEX
            font_scale = 0.7
            thickness = 2
            # 获取文本尺寸以便居中
            (text_w, text_h), baseline = cv2.getTextSize(label, font, font_scale, thickness)
            text_x = (final_width - text_w) // 2
            text_y = bar_height + (text_height + text_h) // 2
            cv2.putText(final_img, label, (text_x, text_y), font, font_scale, (255, 255, 255), thickness, cv2.LINE_AA)

            # 显示图像
            cv2.imshow("MLX90640 Video", final_img)

            # 检测键盘按键
            key = cv2.waitKey(1) & 0xFF
            if key == ord('q'):
                print("[INFO] 用户退出,程序结束。")
                break
            elif key == ord('s'):
                # 按s键时保存图像
                timestamp = time.strftime('%Y%m%d_%H%M%S')
                filename = os.path.join(output_dir, f"ir_image_{timestamp}_{img_count}.png")
                cv2.imwrite(filename, display_img)
                img_count += 1
                print(f"[INFO] 图像保存到: {filename}")

    finally:
        ser.close()
        cv2.destroyAllWindows()

if __name__ == "__main__":
    read_ir_data(port="/dev/ttyACM0",output_dir="1")

About

使用ESP32s3采集红外图像并显示,且将数据上传到上位机,基于PlatformIO开发

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages