使用 Node.JS 为 Python 脚本实现 React UI
如果你熟悉node.js,你就会知道它是
- 超快⚡
- 超可扩展⚖️
- 超强效💥
- 超级简单😁
而且Python拥有强大的科学计算库[NumPy、Pandas 等],使其成为学者、数据科学家、深度学习工程师等的首选。
前段时间,我想探索计算机视觉,这是我长期以来非常着迷的领域。
因此我开始学习 CV,并编写了一个 Python 脚本,该脚本可以获取图像并删除颜色通道,使其看起来就像应用了颜色滤镜一样。
它非常酷,我想用它制作一个有趣的小网站/webUI,以便可以与世界其他地方分享。
作为一名自学成才的MERN Stack开发人员,我开始研究如何结合 python 和 javascript。
一两周后,我做到了。
这个博客记录了我如何解决这个挑战。
我还在这里包含了用于将我的应用程序部署到Heroku 的完整代码
实时部署:https://color-filter.netlify.app
源代码:https://github.com/LucidMach/ColorFilter
它是如何工作的
该项目分为四个阶段
- 网络摄像头 -> React -> NodeJS
- NodeJS Py 子进程
- 实际的 Python 程序
- NodeJS -> React -> Canvas
第一阶段:网络摄像头 -> React -> NodeJS
我们首先从网络摄像头中提取图像,我们可以使用纯 HTML5,navigator.getUserMedia API
但有一个反应包可以简化整个过程。
yarn add react-webcam
我们可以使用getScreenshot({width: 1920, height: 1080})
它来拍摄用户的1080p 快照。
现在我们有了快照(base64字符串),我们必须将其发送到服务器
任何浏览器只能在客户端运行javascript,所以我们必须在服务器上运行 python
我们发出一个帖子请求
axios.post(url, { image: imageSrc, color: selectedColor })
我还发送了所选的颜色,因为我正在构建的应用程序需要它
默认情况下,服务器(bodyParser 中间件)将其可以获取(发布)的数据大小限制为1MB,而图片通常很大
除非你像我之前的项目一样使用了图像优化器
让我们突破极限
app.use(bodyParser.json({ limit: "5mb" }));
我们还需要从 base64 字符串中提取图像
示例 base64 PNG 字符串data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKsAAADVCAMAAAAfHvCaAAAAGFBMVEVY
实际的 base64 图像iVBORw0KGgoAAAANSUhEUgAAAKsAAADVCAMAAAAfHvCaAAAAGFBMVEVY
const base64Image = req.body.image.split(";base64,").pop();
第二阶段:NodeJS Py 子进程
现在我们已经将图像返回到服务器上,我们需要运行 python 脚本
如果你曾经将参数(argv)传递给 Python 脚本/构建过 CLI 工具,那么我们要做的事情非常类似
在此之前,让我们暂时保存图像,因为我们无法将图像作为 argv(脚本参数)传递
const fs = require("fs");
fs.writeFileSync("input/image.png", base64Image, { encoding: "base64" });
现在,我们生成一个 Python 子进程,
我们将终端命令表示为一个数组
const { spawn } = require("child_process");
const py = spawn("python", ["color-filter.py", body.color]);
每个 Python 脚本都可能将数据发送回终端/控制台
为了读取 py 控制台日志,我们创建一个回调函数
var data2send
py.stdout.on("data", (data) => {
data2send = data.toString();
});
console.log(data2send);
第三阶段:实际的 Python 程序
执行 Python 脚本,在我的例子中,它是一个有条件地删除颜色通道的 Numpy 脚本
如果你有兴趣,可以查看github 上的源代码
阶段 4:NodeJS -> React -> Canvas
现在,当 py 子进程终止时,我们需要将图像重新编码为 base64 并发回响应
我们可以通过在子进程结束时锁定回调来实现这一点
py.on("close", () => {
// Adding Heading and converting image to base64
const image = `data:image/png;base64,${fs.readFileSync("output/image.png", {
encoding: "base64",
})}`;
// sending image to client
res.json({ image });
});
奖励阶段:Heroku 部署
这是任何项目中最重要的部分
该过程基本上与部署 vanilla node 应用程序 + python childprocess 的配置完全相同
-
标准部署 Node 到 Heroku
Heroku Node 应用部署文档 -
添加 Python 包
在 JavaScript 世界中,我们有一个package.json
告诉每个节点实例运行所需的所有包
我们为 Python 制作了一些类似的东西requirements.txt
来复制这种行为。
它看起来有点像一个.gitignore
文件
// requirements.txt
numpy
cv2
matplotlib
当 Heroku 注意到该requirements.txt
文件时,它会运行该文件pip install -r requirements.txt
,从而安装所有必需的软件包
- 配置 Buildpacks Heroku Node App 部署文档这是 TL:DR; 版本
// terminal
// This command will set your default buildpack to Node.js
heroku buildpacks:set heroku/nodejs
// This command will set it up so that the Heroku Python buildpack will run first
heroku buildpacks:add --index 1 heroku/python
如果你喜欢这篇博文,请务必在Twitter
上留言
✌️,
LucidMach