跳转到内容

Node-RED 图像处理

Node-RED 图像处理

本节介绍如何在 Node-RED 中接收、处理和显示来自 ESP32-CAM 的图片。学习完成后,您将能够:

  • 在 Node-RED 中安装和配置图片显示节点
  • 接收 MQTT 传输的二进制图片数据
  • 将图片保存到服务器文件系统
  • 在 Dashboard 中实时显示监控画面
┌─────────────────────────────────────────────────────────────┐
│ Node-RED 图片处理流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ [MQTT In: esp32cam/photo] │
│ │ │
│ ├──→ [Function: 转换格式] │
│ │ │ │
│ │ ├──→ [Image Output: 显示预览] │
│ │ │ │
│ │ ├──→ [Write File: 保存到服务器] │
│ │ │ │
│ │ └──→ [Function: 切片处理/Dashboard 输出] │
│ │ │
│ [MQTT In: esp32cam/photo_meta] │
│ │ │
│ └──→ [Function: 记录元数据] → [Debug] │
│ │
└─────────────────────────────────────────────────────────────┘

在 Node-RED 中安装图片输出节点:

Terminal window
# 通过 Node-RED Palette 管理界面安装
# 菜单 → Manage Palette → Install → 搜索 "node-red-contrib-image-output"
# 点击 Install
# 或通过命令行安装 (Docker 环境)
docker exec -it nodered npm install node-red-contrib-image-output

安装完成后,左侧 Palette 将出现新的 image 节点(位于 output 分类下)。

[MQTT In: esp32cam/photo] ──→ [image: 显示图片] ──→ [debug]
参数
Topicesp32cam/photo
QoS1
Outputa parsed JSON object (默认)

注意: 即使图片是二进制数据,MQTT In 节点仍能接收。Node-RED 自动处理二进制 payload,将其作为 Buffer 对象传递。

无需特殊配置,只需将 MQTT In 的输出连接到 Image Output 节点即可自动渲染图片。

部署后触发 ESP32-CAM 拍照,Image 节点将显示:

┌────────────────┐
│ [Image] │
│ ┌──────────┐ │
│ │ │ │
│ │ 照片 │ │
│ │ 预览 │ │
│ │ │ │
│ └──────────┘ │
│ │
│ Size: 32.5KB │
│ 2026-05-18 │
└────────────────┘

为了持久保存图片(供后续推送通知或归档),使用 Write File 节点:

[MQTT In: esp32cam/photo] ──→ [Function: 设置文件名] ──→ [Write File: 保存]
// Function: 设置文件保存参数
// 为图片文件生成带时间戳的文件名
var filePath = "/data/esp32cam/photo_" + Date.now() + ".jpg";
// 可以改为覆盖模式,只保留最新一张
// var filePath = "/data/esp32cam/latest.jpg";
msg.filename = filePath;
msg.payload = msg.payload; // 保持二进制数据不变
return msg;
参数
Filenamemsg.filename (由 Function 节点设置)
Actionoverwrite file (或 append to file)
Create directory if needed✅ 勾选
Terminal window
# 进入 Node-RED Docker 容器
docker exec -it nodered ls -la /data/esp32cam/
# 输出示例:
# -rw-r--r-- 1 node-red node-red 33280 May 18 14:30:25 photo_1716013825000.jpg
# -rw-r--r-- 1 node-red node-red 28901 May 18 14:35:12 photo_1716014112000.jpg
# 查看最新图片
docker exec -it nodered cat /data/esp32cam/latest.jpg > ~/latest_photo.jpg
open ~/latest_photo.jpg

将图片显示集成到 Node-RED Dashboard:

Terminal window
# 如果尚未安装
npm install node-red-dashboard
# 或通过 Palette 搜索安装
[MQTT In: esp32cam/photo]
├──→ [Function: 编码为 base64]
│ │
│ └──→ [ui_template: 显示图片]
└──→ [Function: 提取元数据]
└──→ [ui_text: 状态信息]
<!-- ui_template: ESP32-CAM 图片显示 -->
<div style="text-align: center; padding: 10px;">
<img id="camImage"
src="data:image/jpeg;base64,{{msg.payload}}"
style="max-width: 100%; border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);">
<p style="color: #666; font-size: 12px; margin-top: 5px;">
最后更新: {{msg.topic}}
</p>
</div>
// Function: 将二进制 Buffer 编码为 Base64 字符串
// 供 ui_template 显示
// msg.payload 是二进制 Buffer
msg.payload = msg.payload.toString('base64');
// 附加元数据
msg.topic = new Date().toLocaleString();
return msg;

Dashboard 布局示例:

┌──────────────────────────────────────────────┐
│ 📷 远程巡检 - 实时监控 │
├──────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────┐ │
│ │ │ │
│ │ ESP32-CAM 实时画面 │ │
│ │ │ │
│ │ │ │
│ └──────────────────────────────────────┘ │
│ │
│ 📊 状态: 在线 📸 上次拍照: 14:30:25 │
│ 📏 照片大小: 32.5 KB │
│ │
│ [📷 拍照] [💡 闪光灯] [⏰ 定时 30分] │
│ │
└──────────────────────────────────────────────┘

为避免服务器磁盘空间被图片占满,添加定时清理机制:

// Function: 定时清理旧图片
// 由 Inject 节点每小时触发
var fs = require('fs');
var path = '/data/esp32cam/';
var maxAge = 7 * 24 * 60 * 60 * 1000; // 7 天
var now = Date.now();
var deleted = 0;
try {
var files = fs.readdirSync(path);
files.forEach(function(file) {
var filePath = path + file;
var stats = fs.statSync(filePath);
if (now - stats.mtimeMs > maxAge) {
fs.unlinkSync(filePath);
deleted++;
node.warn("Deleted old photo: " + file);
}
});
msg.payload = "Cleaned up " + deleted + " old photos";
} catch (e) {
msg.payload = "Cleanup error: " + e.message;
}
return msg;
Terminal window
# Inject 节点配置
# 定时: cron 表达式 "0 * * * *" (每小时整点)
Terminal window
# 1. 触发拍照
mosquitto_pub -t "esp32cam/command" -m "take_photo"
# 2. 检查 Node-RED Image 节点是否显示图片
# 3. 检查文件系统
docker exec -it nodered ls -la /data/esp32cam/
# 4. 检查 Dashboard 是否更新
# 打开浏览器访问 http://<node-red-ip>:1880/ui
# 5. 测试定时清理
mosquitto_pub -t "esp32cam/command" -m "cleanup"

原因: MQTT 传输的 JPEG 质量设置过低,或分辨率太小。

解决方案: 调整 ESP32 的 JPEG 质量参数:

// 在 ESP32 摄像头配置中调整
config.jpeg_quality = 12; // 默认 12 (0-63, 越小质量越好)
config.frame_size = FRAMESIZE_VGA; // 640×480
// 或使用 FRAMESIZE_SVGA (800×600), FRAMESIZE_XGA (1024×768)

Q2: Node-RED 接收图片时内存不足?

Section titled “Q2: Node-RED 接收图片时内存不足?”

场景: 频繁拍照导致 Node-RED 内存持续增长。

解决方案:

  1. 增加 Node-RED 的 --max-old-space-size 参数
  2. 限制图片分辨率不超过 VGA
  3. 增加拍照间隔(至少 10 秒)
# docker-compose.yml 中调整 Node-RED 内存
services:
nodered:
image: nodered/node-red:latest
environment:
- NODE_OPTIONS=--max-old-space-size=256

Q3: 如何保存多张图片而不是覆盖?

Section titled “Q3: 如何保存多张图片而不是覆盖?”

修改 Function 节点,使用计数器或随机数生成文件名:

// 使用时间戳 + 随机数
var filePath = "/data/esp32cam/photo_" +
Date.now() + "_" +
Math.random().toString(36).substr(2, 5) + ".jpg";

推荐做法:

  • 使用独立的 Topic 传输图片数据和元数据
  • Image Output 节点配合 Debug 节点排查传输问题
  • 图片文件按日期分目录存储 (/data/esp32cam/2026/05/18/)
  • 定期清理 7 天前的历史图片
  • Dashboard 中使用 Base64 内联显示而非文件 URL

避免做法:

  • 在 Function 节点中对大图片进行 JSON 序列化
  • 不限制图片保存数量导致磁盘占满
  • 多个图片节点共用相同的文件名
  • 直接在 Dashboard 中显示超过 500KB 的大图
  1. node-red-contrib-image-output 可直接显示 MQTT 传输的二进制图片
  2. Write File 节点将图片持久化到服务器文件系统
  3. Dashboard UI Template 通过 Base64 编码显示最新监控画面
  4. 定时清理机制防止磁盘空间被历史图片占满
  5. 图片分辨率和质量在 ESP32 端控制

正在开发商业 IoT 产品?

我们提供 ESP32 ODM 定制设计与制造服务。从原型到量产——编写这套教程的团队,可以和你一起实现。

联系我们 →