Node.js环境下的实时口罩检测API开发与部署教程

张开发
2026/4/4 10:55:26 15 分钟阅读
Node.js环境下的实时口罩检测API开发与部署教程
Node.js环境下的实时口罩检测API开发与部署教程1. 引言在当今的智能化场景中实时口罩检测技术已经成为许多公共场所和企业的必备功能。无论是商场入口、办公大楼还是公共交通场所快速准确地检测人员是否佩戴口罩都显得尤为重要。本教程将手把手教你如何使用Node.js开发一个完整的实时口罩检测RESTful API从环境搭建到性能优化再到错误处理和实际部署。即使你是刚接触Node.js的开发者也能跟着步骤一步步实现这个实用的功能。学完本教程后你将掌握如何构建一个能够处理图像数据、进行实时分析并返回检测结果的高性能API为你的项目添加实用的计算机视觉能力。2. 环境准备与Node.js配置2.1 Node.js安装与验证首先确保你的系统已经安装了Node.js。推荐使用LTS版本以获得更好的稳定性# 检查Node.js是否已安装 node --version # 如果未安装访问Node.js官网下载安装包 # 或者使用nvmNode版本管理器安装 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash nvm install --lts nvm use --lts安装完成后创建一个新的项目目录并初始化mkdir mask-detection-api cd mask-detection-api npm init -y2.2 核心依赖安装我们需要安装几个关键包来构建我们的API# Express.js用于构建Web服务器 npm install express # Multer用于处理文件上传 npm install multer # TensorFlow.js用于机器学习推理 npm install tensorflow/tfjs-node # 图像处理库 npm install sharp canvas # 其他工具库 npm install cors dotenv2.3 口罩检测模型准备对于实时口罩检测我们可以使用预训练的TensorFlow.js模型。这里我们准备一个简单的口罩检测模型// model-loader.js const tf require(tensorflow/tfjs-node); const fs require(fs); const path require(path); class MaskDetector { constructor() { this.model null; this.labels [with_mask, without_mask]; } async loadModel(modelPath) { try { console.log(正在加载口罩检测模型...); this.model await tf.loadLayersModel(file://${modelPath}/model.json); console.log(模型加载成功); } catch (error) { console.error(模型加载失败:, error); throw error; } } async detect(imageTensor) { if (!this.model) { throw new Error(模型未加载请先调用loadModel方法); } // 预处理图像 const resized tf.image.resizeBilinear(imageTensor, [224, 224]); const normalized resized.div(255.0); const batched normalized.expandDims(0); // 进行预测 const predictions this.model.predict(batched); const result predictions.argMax(1).dataSync()[0]; // 清理内存 resized.dispose(); normalized.dispose(); batched.dispose(); predictions.dispose(); return { label: this.labels[result], confidence: predictions.max().dataSync()[0] }; } } module.exports MaskDetector;3. 构建RESTful API3.1 初始化Express服务器创建一个基本的Express服务器结构// app.js const express require(express); const multer require(multer); const cors require(cors); const fs require(fs); const path require(path); const MaskDetector require(./model-loader); const app express(); const port process.env.PORT || 3000; // 中间件配置 app.use(cors()); app.use(express.json({ limit: 10mb })); app.use(express.urlencoded({ extended: true })); // 确保上传目录存在 const uploadDir path.join(__dirname, uploads); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } // Multer配置用于文件上传 const storage multer.diskStorage({ destination: function (req, file, cb) { cb(null, uploadDir); }, filename: function (req, file, cb) { cb(null, Date.now() - file.originalname); } }); const upload multer({ storage: storage, limits: { fileSize: 5 * 1024 * 1024 } // 限制5MB }); // 初始化口罩检测器 const detector new MaskDetector(); // 加载模型在实际应用中应该使用异步初始化 detector.loadModel(path.join(__dirname, models)) .then(() console.log(API准备就绪)) .catch(err console.error(初始化失败:, err)); module.exports { app, upload, detector };3.2 实现检测端点创建主要的API端点来处理图像检测请求// routes/detect.js const express require(express); const router express.Router(); const tf require(tensorflow/tfjs-node); const sharp require(sharp); const { detector } require(../app); // 处理图像上传检测 router.post(/upload, async (req, res) { try { if (!req.file) { return res.status(400).json({ error: 请提供图像文件 }); } // 读取并预处理图像 const imageBuffer await sharp(req.file.path) .resize(224, 224) .toBuffer(); const imageTensor tf.node.decodeImage(imageBuffer); const detectionResult await detector.detect(imageTensor); // 清理临时文件 tf.dispose(imageTensor); res.json({ success: true, result: detectionResult, timestamp: new Date().toISOString() }); } catch (error) { console.error(检测错误:, error); res.status(500).json({ error: 处理图像时发生错误, message: error.message }); } }); // 处理Base64图像检测 router.post(/base64, async (req, res) { try { const { image } req.body; if (!image) { return res.status(400).json({ error: 请提供Base64编码的图像 }); } // 移除Base64前缀 const base64Data image.replace(/^data:image\/\w;base64,/, ); const imageBuffer Buffer.from(base64Data, base64); const imageTensor tf.node.decodeImage(imageBuffer); const detectionResult await detector.detect(imageTensor); tf.dispose(imageTensor); res.json({ success: true, result: detectionResult, timestamp: new Date().toISOString() }); } catch (error) { console.error(Base64检测错误:, error); res.status(500).json({ error: 处理Base64图像时发生错误, message: error.message }); } }); module.exports router;3.3 添加健康检查端点// routes/health.js const express require(express); const router express.Router(); router.get(/, (req, res) { res.json({ status: healthy, timestamp: new Date().toISOString(), uptime: process.uptime(), memory: process.memoryUsage() }); }); module.exports router;4. 性能优化策略4.1 内存管理优化TensorFlow.js操作会占用大量内存需要仔细管理// utils/memory-manager.js class MemoryManager { constructor() { this.tensors new Set(); } track(tensor) { this.tensors.add(tensor); return tensor; } disposeAll() { this.tensors.forEach(tensor { if (!tensor.isDisposed) { tensor.dispose(); } }); this.tensors.clear(); } // 定期清理内存 startCleanupInterval(intervalMs 60000) { setInterval(() { tf.tidy(() {}); if (tf.memory().numTensors 100) { tf.disposeVariables(); } }, intervalMs); } } module.exports MemoryManager;4.2 请求批处理对于高并发场景实现请求批处理可以显著提高性能// utils/batch-processor.js class BatchProcessor { constructor(batchSize 10, timeoutMs 100) { this.batchSize batchSize; this.timeoutMs timeoutMs; this.batch []; this.timeoutId null; } async addRequest(request) { return new Promise((resolve, reject) { this.batch.push({ request, resolve, reject }); if (this.batch.length this.batchSize) { this.processBatch(); } else if (!this.timeoutId) { this.timeoutId setTimeout(() this.processBatch(), this.timeoutMs); } }); } async processBatch() { if (this.timeoutId) { clearTimeout(this.timeoutId); this.timeoutId null; } if (this.batch.length 0) return; const currentBatch [...this.batch]; this.batch []; try { // 批量处理逻辑 const results await this.processImagesInBatch( currentBatch.map(item item.request) ); currentBatch.forEach((item, index) { item.resolve(results[index]); }); } catch (error) { currentBatch.forEach(item { item.reject(error); }); } } async processImagesInBatch(images) { // 实现批量图像处理逻辑 // 这里可以使用TensorFlow的批处理能力 return images.map(() ({ label: processed, confidence: 0.9 })); } }5. 错误处理与日志记录5.1 全局错误处理中间件// middleware/error-handler.js function errorHandler(err, req, res, next) { console.error(全局错误:, { message: err.message, stack: err.stack, url: req.url, method: req.method, timestamp: new Date().toISOString() }); // 根据错误类型返回不同的状态码 if (err.name ValidationError) { return res.status(400).json({ error: 请求参数无效, details: err.message }); } if (err.message.includes(模型)) { return res.status(503).json({ error: 服务暂时不可用, message: 模型加载中或出现错误 }); } res.status(500).json({ error: 服务器内部错误, message: process.env.NODE_ENV development ? err.message : 请稍后重试 }); } module.exports errorHandler;5.2 请求日志中间件// middleware/logger.js function requestLogger(req, res, next) { const start Date.now(); res.on(finish, () { const duration Date.now() - start; console.log({ method: req.method, url: req.url, status: res.statusCode, duration: ${duration}ms, timestamp: new Date().toISOString(), userAgent: req.get(User-Agent) }); }); next(); } module.exports requestLogger;6. 部署与生产环境配置6.1 PM2进程管理创建PM2配置文件// ecosystem.config.js module.exports { apps: [{ name: mask-detection-api, script: ./server.js, instances: max, exec_mode: cluster, env: { NODE_ENV: production, PORT: 3000 }, max_memory_restart: 1G, watch: false, merge_logs: true, error_file: ./logs/error.log, out_file: ./logs/out.log, log_file: ./logs/combined.log }] };6.2 Docker容器化部署创建Dockerfile# Dockerfile FROM node:18-slim WORKDIR /app # 安装系统依赖 RUN apt-get update apt-get install -y \ python3 \ make \ g \ rm -rf /var/lib/apt/lists/* # 复制package文件 COPY package*.json ./ RUN npm install --production # 复制应用代码 COPY . . # 创建非root用户 RUN useradd -m appuser USER appuser # 暴露端口 EXPOSE 3000 # 启动应用 CMD [npm, start]创建docker-compose.ymlversion: 3.8 services: mask-api: build: . ports: - 3000:3000 environment: - NODE_ENVproduction - PORT3000 volumes: - ./models:/app/models - ./logs:/app/logs restart: unless-stopped7. 完整服务器入口文件// server.js require(dotenv).config(); const { app, upload } require(./app); const detectRoutes require(./routes/detect); const healthRoutes require(./routes/health); const errorHandler require(./middleware/error-handler); const requestLogger require(./middleware/logger); // 中间件 app.use(requestLogger); // 路由 app.use(/api/health, healthRoutes); app.use(/api/detect, detectRoutes); // 根路径 app.get(/, (req, res) { res.json({ message: 口罩检测API服务运行中, version: 1.0.0, endpoints: { health: /api/health, detect: /api/detect/upload (POST), base64: /api/detect/base64 (POST) } }); }); // 错误处理必须放在最后 app.use(errorHandler); // 启动服务器 const PORT process.env.PORT || 3000; app.listen(PORT, () { console.log(服务器运行在端口 ${PORT}); console.log(环境: ${process.env.NODE_ENV || development}); }); // 优雅关闭 process.on(SIGINT, () { console.log(正在关闭服务器...); process.exit(0); });8. 测试API接口使用curl测试你的API# 健康检查 curl http://localhost:3000/api/health # 使用文件上传检测 curl -X POST -F imagetest.jpg http://localhost:3000/api/detect/upload # 使用Base64检测 curl -X POST -H Content-Type: application/json \ -d {image:base64编码的图像数据} \ http://localhost:3000/api/detect/base649. 总结通过这个教程我们完整地构建了一个基于Node.js的实时口罩检测API。从环境配置、模型加载到API开发、性能优化和错误处理每个环节都进行了详细的实现。实际使用中这个API可以轻松集成到各种应用中比如门禁系统、安防监控或者移动应用中。性能方面通过内存管理、请求批处理和集群部署能够处理相当高的并发请求。如果你想要进一步提升检测精度可以考虑使用更先进的预训练模型或者收集特定场景的数据进行模型微调。另外加入Redis缓存频繁检测的结果、使用消息队列处理峰值流量都是不错的扩展方向。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

更多文章