DeOldify图像上色服务Node.js调用实战:构建自动化批处理工具
DeOldify图像上色服务Node.js调用实战构建自动化批处理工具你是不是也遇到过这样的情况手头有一大堆珍贵的老照片都是黑白的想给它们上色却无从下手。一张张手动处理那得花多少时间啊。或者你所在的媒体、出版机构有海量的历史图片档案需要数字化和色彩修复人工操作的成本高得吓人。别担心今天我们就来解决这个问题。我会带你用Node.js亲手搭建一个自动化工具让它帮你批量调用DeOldify图像上色服务。你只需要把图片文件夹准备好剩下的交给程序它就能自动完成上色、保存甚至生成一份处理报告。整个过程就像有个不知疲倦的助手在帮你干活。这篇文章我们就来聊聊怎么把这个“助手”造出来。从Node.js环境怎么配到怎么用代码跟DeOldify服务“对话”再到怎么让这个工具“多线程”干活跑得更快我都会一步步讲清楚。如果你对JavaScript有点了解或者想学点实用的自动化技能那这篇正适合你。1. 准备工作搭建你的Node.js“工作台”工欲善其事必先利其器。在开始写代码之前我们得先把“工作台”搭好。这里主要就是两件事安装Node.js和准备一个DeOldify服务。1.1 Node.js安装及环境配置首先我们得请出今天的主角——Node.js。你可以把它理解为一个能让JavaScript代码在电脑上而不是只在浏览器里运行的环境。我们的自动化工具就是用JavaScript写的所以离不开它。第一步下载和安装。去Node.js的官方网站找到下载页面。建议选择标有“LTS”长期支持版的版本这个版本更稳定。下载下来后直接运行安装程序一路“下一步”就行安装过程很简单。怎么确认安装成功了呢打开你的命令行工具Windows上是命令提示符或PowerShellMac或Linux上是终端输入下面这行命令然后按回车node -v如果屏幕上显示出一个版本号比如v18.17.0那就恭喜你Node.js安装成功了同样再输入npm -v看看这个npm是Node.js自带的包管理器我们待会儿用它来安装其他工具库它也应该能显示出版本号。第二步创建项目文件夹。在你的电脑上找个合适的地方新建一个文件夹名字可以叫deoldify-batch-tool。然后在这个文件夹里再打开命令行。第三步初始化项目。在命令行里进入你刚创建的文件夹然后运行npm init -y这个命令会快速生成一个package.json文件它就像是这个项目的“身份证”和“说明书”记录着项目信息以及需要用到的工具库。1.2 获取DeOldify服务访问点我们的工具需要和DeOldify服务通信。通常DeOldify会以API服务的形式提供。你需要先确保有一个可用的DeOldify服务端点Endpoint。这个端点可能是一个URL比如http://your-deoldify-server:5000/colorize。怎么获得这个服务呢有几个常见途径自行部署如果你有GPU服务器可以按照DeOldify开源项目的指南自己部署一个服务。使用云服务有些云平台提供了预置的AI模型服务其中可能包含DeOldify。团队或公司内部服务可能你们的技术团队已经部署好了。拿到这个服务地址URL后先记下来我们后面的代码里会用到它。为了安全起见我们通常不把这个地址直接写在代码里而是放在环境变量中。2. 核心工具打造编写批处理脚本环境准备好了服务地址也有了现在可以动手写我们工具的核心部分了。我们将创建几个JavaScript文件分别负责不同的任务。2.1 项目结构与依赖安装首先规划一下我们的项目结构这样代码更清晰deoldify-batch-tool/ ├── input/ # 存放待处理的黑白图片 ├── output/ # 存放处理后的彩色图片 ├── reports/ # 存放生成的处理报告 ├── src/ │ ├── config.js # 配置文件 │ ├── apiClient.js # 负责调用DeOldify API │ ├── batchProcessor.js # 核心的批处理逻辑 │ └── reportGenerator.js # 生成报告 ├── main.js # 程序主入口 └── package.json然后安装我们需要的工具库。在项目根目录的命令行里运行npm install axios fs-extra pathaxios一个非常好用的库用来发送HTTP请求我们将用它来调用DeOldify的API。fs-extra这是Node.js原生fs模块的增强版提供了更多好用的文件操作功能比如方便地复制文件、确保目录存在等。pathNode.js自带的模块用于处理文件和目录的路径。2.2 构建API客户端我们先来写一个专门负责和DeOldify服务“说话”的模块。在src文件夹下创建apiClient.js文件。// src/apiClient.js const axios require(axios); const FormData require(form-data); const fs require(fs); const path require(path); class DeOldifyClient { constructor(apiBaseUrl) { // 初始化时传入DeOldify服务的地址 this.client axios.create({ baseURL: apiBaseUrl, timeout: 300000, // 设置一个较长的超时时间因为图片处理可能较慢 }); } /** * 调用DeOldify服务为单张图片上色 * param {string} imagePath - 本地黑白图片的路径 * returns {PromiseBuffer} - 返回处理后的彩色图片数据 */ async colorizeImage(imagePath) { try { // 1. 创建一个表单数据对象模拟网页上传文件 const formData new FormData(); // 读取图片文件并以‘image’为字段名添加到表单 formData.append(image, fs.createReadStream(imagePath)); // 2. 发送POST请求到DeOldify服务 // 注意具体的API路径如 /colorize需要根据你的DeOldify服务实际情况调整 const response await this.client.post(/colorize, formData, { headers: { ...formData.getHeaders(), // 设置正确的表单请求头 }, responseType: arraybuffer, // 指定响应类型为二进制数据流 }); console.log(图片处理成功: ${path.basename(imagePath)}); // 3. 返回图片的二进制数据 return Buffer.from(response.data); } catch (error) { console.error(处理图片失败 [${path.basename(imagePath)}]:, error.message); // 可以选择抛出错误或者返回null由上层逻辑决定如何处理失败 throw new Error(API调用失败: ${error.message}); } } } module.exports DeOldifyClient;这段代码的核心是colorizeImage方法。它做了三件事把本地的图片文件“打包”成网络请求能识别的格式把这个“包裹”发送给DeOldify服务最后把服务返回的彩色图片数据接住并转换成我们可以保存的格式。2.3 实现批量处理与并发控制如果有一万张图片一张一张处理那得等到猴年马月。所以我们要让程序能“同时”处理多张图片。这里我们用Promise.all配合“并发池”的概念来控制同时处理的任务数量避免一下子发出太多请求把服务器压垮。在src文件夹下创建batchProcessor.js。// src/batchProcessor.js const fs require(fs-extra); const path require(path); const { promisify } require(util); const pipeline promisify(require(stream).pipeline); class BatchProcessor { constructor(apiClient, concurrency 3) { this.apiClient apiClient; // 传入上面写好的API客户端 this.concurrency concurrency; // 并发数默认同时处理3张 this.results []; // 用于记录每张图片的处理结果 } /** * 处理单个图片的完整流程 * param {string} inputPath - 输入图片路径 * param {string} outputDir - 输出目录 * returns {PromiseObject} - 返回该图片的处理结果信息 */ async processSingleImage(inputPath, outputDir) { const startTime Date.now(); const fileName path.basename(inputPath); const outputPath path.join(outputDir, fileName); const result { fileName, inputPath, outputPath, success: false, error: null, duration: 0, }; try { // 1. 调用API客户端进行上色 const imageBuffer await this.apiClient.colorizeImage(inputPath); // 2. 将返回的图片数据保存到输出目录 await fs.writeFile(outputPath, imageBuffer); const endTime Date.now(); result.success true; result.duration endTime - startTime; console.log(✅ 已完成: ${fileName} (${result.duration}ms)); } catch (error) { const endTime Date.now(); result.success false; result.error error.message; result.duration endTime - startTime; console.error(❌ 失败: ${fileName} - ${error.message}); } return result; } /** * 核心的批量并发处理方法 * param {Arraystring} imagePaths - 所有待处理图片的路径数组 * param {string} outputDir - 输出目录 * returns {PromiseArray} - 返回所有图片的处理结果数组 */ async processBatch(imagePaths, outputDir) { console.log(开始批量处理共 ${imagePaths.length} 张图片并发数: ${this.concurrency}); this.results []; // 使用一个“任务池”来控制并发 for (let i 0; i imagePaths.length; i this.concurrency) { // 每次取出“并发数”个任务 const batch imagePaths.slice(i, i this.concurrency); // 同时执行这一批任务并等待它们全部完成 const batchResults await Promise.all( batch.map(imagePath this.processSingleImage(imagePath, outputDir)) ); // 将这批任务的结果保存起来 this.results.push(...batchResults); console.log(进度: ${Math.min(i this.concurrency, imagePaths.length)}/${imagePaths.length}); } console.log(批量处理完成); return this.results; } /** * 获取处理结果的统计信息 */ getStats() { const total this.results.length; const successful this.results.filter(r r.success).length; const failed total - successful; const totalTime this.results.reduce((sum, r) sum r.duration, 0); const avgTime total 0 ? totalTime / total : 0; return { total, successful, failed, totalTime: ${(totalTime / 1000).toFixed(2)}s, avgTime: ${avgTime.toFixed(0)}ms, }; } } module.exports BatchProcessor;这段代码是工具的大脑。processBatch方法负责调度它把一大堆图片任务分成小批每一批同时处理几张由concurrency控制等这一批全部干完再开始下一批。processSingleImage方法则是具体干活的调用API、保存图片、记录成功或失败。最后getStats方法能给我们一份简单的统计报告。2.4 生成处理报告处理完图片我们当然想知道结果如何成功了多少失败了哪些花了多长时间在src文件夹下创建reportGenerator.js。// src/reportGenerator.js const fs require(fs-extra); const path require(path); class ReportGenerator { /** * 生成HTML格式的详细处理报告 * param {Array} results - 批处理结果数组 * param {Object} stats - 统计信息 * param {string} outputPath - 报告输出路径 */ static async generateHtmlReport(results, stats, outputPath) { const failedItems results.filter(r !r.success); const htmlContent !DOCTYPE html html head titleDeOldify 批量处理报告/title style body { font-family: sans-serif; margin: 40px; line-height: 1.6; } .summary { background-color: #f4f4f4; padding: 20px; border-radius: 8px; margin-bottom: 30px; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 15px; } .stat-card { background: white; padding: 15px; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); text-align: center; } .stat-card h3 { margin-top: 0; color: #333; } .stat-card .number { font-size: 2em; font-weight: bold; margin: 10px 0; } .success { color: #2ecc71; } .failed { color: #e74c3c; } table { width: 100%; border-collapse: collapse; margin-top: 20px; } th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #f8f9fa; } tr:hover { background-color: #f5f5f5; } /style /head body h1 DeOldify 批量上色处理报告/h1 p生成时间: ${new Date().toLocaleString()}/p div classsummary h2处理概览/h2 div classstats-grid div classstat-card h3总图片数/h3 div classnumber${stats.total}/div /div div classstat-card success h3成功/h3 div classnumber${stats.successful}/div /div div classstat-card failed h3失败/h3 div classnumber${stats.failed}/div /div div classstat-card h3平均耗时/h3 div classnumber${stats.avgTime}/div /div /div /div h2失败详情/h2 ${failedItems.length 0 ? table thead tr th文件名/th th错误信息/th th耗时/th /tr /thead tbody ${failedItems.map(item tr td${item.fileName}/td td${item.error || 未知错误}/td td${item.duration}ms/td /tr ).join()} /tbody /table : p 所有图片均处理成功/p} /body /html ; await fs.writeFile(outputPath, htmlContent); console.log(处理报告已生成: ${outputPath}); } /** * 生成简明的JSON格式报告便于其他程序读取 * param {Array} results - 批处理结果数组 * param {Object} stats - 统计信息 * param {string} outputPath - 报告输出路径 */ static async generateJsonReport(results, stats, outputPath) { const report { generatedAt: new Date().toISOString(), statistics: stats, results: results }; await fs.writeJson(outputPath, report, { spaces: 2 }); // spaces: 2 让JSON文件有缩进便于阅读 console.log(JSON报告已生成: ${outputPath}); } } module.exports ReportGenerator;这个报告生成器提供了两种格式的报告一个是直观的HTML网页在浏览器里打开就能看有图表有表格另一个是结构化的JSON文件方便你如果需要进一步分析数据可以用程序直接读取。3. 组装与运行让工具动起来各个零件都造好了现在我们把它们组装起来并写一个主程序来启动整个流程。在项目根目录创建main.js。// main.js const fs require(fs-extra); const path require(path); const DeOldifyClient require(./src/apiClient); const BatchProcessor require(./src/batchProcessor); const ReportGenerator require(./src/reportGenerator); // 配置信息 const CONFIG { // 从环境变量读取API地址如果没设置则使用默认值记得替换成你的地址 DEOILDIFY_API_URL: process.env.DEOILDIFY_API_URL || http://localhost:5000, INPUT_DIR: path.join(__dirname, input), // 输入图片目录 OUTPUT_DIR: path.join(__dirname, output), // 输出图片目录 REPORT_DIR: path.join(__dirname, reports), // 报告输出目录 CONCURRENCY: 3, // 并发处理数可根据你的网络和服务性能调整 }; async function main() { console.log( 开始DeOldify批量上色任务...\n); // 1. 检查并创建必要的目录 await fs.ensureDir(CONFIG.INPUT_DIR); await fs.ensureDir(CONFIG.OUTPUT_DIR); await fs.ensureDir(CONFIG.REPORT_DIR); // 2. 获取输入目录中的所有图片文件这里以.jpg, .png为例 const imageFiles await fs.readdir(CONFIG.INPUT_DIR); const imagePaths imageFiles .filter(file /\.(jpg|jpeg|png|bmp)$/i.test(file)) // 过滤出图片文件 .map(file path.join(CONFIG.INPUT_DIR, file)); if (imagePaths.length 0) { console.log(在目录 ${CONFIG.INPUT_DIR} 中未找到图片文件。); console.log(请将待处理的图片放入该目录然后重新运行程序。); return; } console.log(找到 ${imagePaths.length} 张待处理图片。); // 3. 初始化客户端和处理器 const apiClient new DeOldifyClient(CONFIG.DEOILDIFY_API_URL); const processor new BatchProcessor(apiClient, CONFIG.CONCURRENCY); // 4. 执行批量处理 const results await processor.processBatch(imagePaths, CONFIG.OUTPUT_DIR); // 5. 生成报告 const stats processor.getStats(); const timestamp new Date().toISOString().replace(/[:.]/g, -); const htmlReportPath path.join(CONFIG.REPORT_DIR, report_${timestamp}.html); const jsonReportPath path.join(CONFIG.REPORT_DIR, report_${timestamp}.json); await ReportGenerator.generateHtmlReport(results, stats, htmlReportPath); await ReportGenerator.generateJsonReport(results, stats, jsonReportPath); // 6. 在控制台打印最终统计 console.log(\n .repeat(50)); console.log( 批量处理任务完成); console.log(.repeat(50)); console.log(总计处理: ${stats.total} 张); console.log(成功: ${stats.successful} 张); console.log(失败: ${stats.failed} 张); console.log(总耗时: ${stats.totalTime}); console.log(平均每张: ${stats.avgTime}); console.log(详细报告: ${htmlReportPath}); } // 启动程序并捕获可能的错误 main().catch(error { console.error(程序运行出错:, error); process.exit(1); // 非正常退出 });这个主程序就像乐高说明书它按顺序执行了所有步骤检查环境、找图片、初始化工具、开始处理、最后生成报告。运行前记得把你要处理的黑白图片都放到项目根目录下的input文件夹里。如何运行在项目根目录打开命令行输入node main.js然后泡杯咖啡看着命令行窗口刷刷地打印处理进度吧。处理完的彩色图片会保存在output文件夹详细的报告在reports文件夹里。4. 总结与展望整个工具搭建下来感觉怎么样其实核心思路并不复杂准备环境、写好与AI服务通信的模块、实现一个能“多线程”工作的批处理器、最后把结果整理成报告。这个模式不仅可以用于图片上色稍加修改也能套用到其他需要批量调用AI服务的场景比如批量识别图片内容、批量生成文本摘要等等。实际用起来有几个小经验可以分享。一是并发数CONCURRENCY不要设得太高一般3-5个比较稳妥设太高可能会把服务打挂或者被限制请求。二是输入图片的格式和大小最好先统一处理一下避免因为某张奇怪的图片导致整个任务卡住。三是这个报告生成模块还挺有用的特别是处理大量图片时能一眼看清哪些失败了方便后续排查。你可以在这个基础上继续“装修”你的工具。比如增加一个重试机制某张图片失败了自动再试两次或者加个进度条看起来更直观再或者把配置信息单独放到一个config.json文件里修改起来更方便。工具嘛就是越用越顺手根据你自己的需求慢慢调整就好。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2464424.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!