我正在尝试在 python 脚本中启动 javascript 子进程。
我想使用 Human repo 进行一些照片分析,它没有任何 Python 移植(原生 js),所以我必须在 javascript 中执行他的
detect
函数
总体思路是启动Python代码从网络摄像头拍照(这是项目的限制),然后在js脚本中处理照片。
(最好的办法是不要保存照片,而是直接将其传递给js脚本,我尝试了
frame_json = json.dumps(frame.tolist())
,然后process.communicate(input=frame_json)
,但无论如何都不起作用)
这是我的Python代码:
import cv2
import json
import subprocess
import asyncio
def capture():
video_capture = cv2.VideoCapture(0)
while True:
# Grab a single frame of video
ret, frame = video_capture.read()
if not ret:
break
#cv2.imwrite('photo1.png', frame)
try:
js_command = ['node', 'detect.js']
process = subprocess.Popen(js_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
output, output2 = process.communicate(input='photo1.png')
print(f'h_res: {output}')
return output.strip()
except Exception as e:
print(e)
return None
capture()
而这是 javascript:
const tf = require('@tensorflow/tfjs-node');
const Human = require('@vladmandic/human').default; // points to @vladmandic/human/dist/human.node.js
const fs = require('fs');
process.stdin.setEncoding('utf-8');
const config = {
modelBasePath: 'file://HumanNPM/node_modules/@vladmandic/human/models',
body: { enabled: true, modelPath: 'file://node_modules/@vladmandic/human/models/models.json' },
};
function newFunction(inputFile) {
const human = new Human(config);
const buffer = fs.readFileSync(inputFile); // read file content into a binary buffer
const tensor = human.tf.node.decodeImage(buffer); // decode jpg/png data to raw pixels
res = human.detect(tensor, config).then((result) => {
process.stdout.write(result);
console.log(result)
return result;
});
return res
}
process.stdin.on('data', function (data) {
newFunction(data)
});
process.stdin.on('end', function () {
process.exit();
});
问题是 Human 库似乎没有执行,因为我在 python 输出中没有看到任何内容。 显然,如果我从 js 中注释掉 Human 部分和
console.log('something')
,我就可以在我的 Python 控制台中看到它。
我不知道是否有我遗漏的东西。
有并发问题吗?或者我是否有可能以某种方式错误地使用了该库? (如果单独使用该库而不用作子进程,则该库仍然可以正常工作,
node detect.js
)。
有人可以帮助我吗?
由于数据传递和子流程管理的复杂性,通过子流程将基于 JavaScript 的照片分析集成到 Python 项目中可能会相当复杂。您的方法有坚实的基础,但有一些关键的调整和注意事项可以解决您面临的问题。
Python 和 JavaScript 之间的数据传递
您当前的方法尝试将图像文件路径直接作为子进程的输入传递,这似乎与您最初的目标(直接传递图像数据)有点偏离。由于直接数据传递(如图像字节或 JSON 表示形式)无法按预期工作,因此使用临时文件来桥接 Python 和 JavaScript 之间的数据可能是最直接的方法,尽管不是最有效的方法。
但是,为了坚持您最初尝试直接数据传递,请确保您的 JavaScript 脚本正确解析来自 Python 的输入数据。在 JavaScript 代码中,您将输入数据视为文件路径 (fs.readFileSync(inputFile);),如果直接传递图像数据,则该路径将不起作用。如果您想避免使用中间文件,您需要调整它来处理原始图像数据。
处理异步 JavaScript 代码
您的 JavaScript 函数 newFunction 使用异步代码( human.detect(tensor, config).then(...) ),但在从 Python 调用的上下文中无法正确处理此问题。您需要确保 Node.js 脚本在完成处理后正确地向 Python 脚本发出信号,尤其是在处理异步操作时。
一个快速解决方法是在 JavaScript 代码中使用异步函数包装器,并等待检测函数完成,然后再写入 stdout 并退出:
async function processImage(data) {
const human = new Human(config);
const tensor = human.tf.node.decodeImage(data);
const result = await human.detect(tensor, config);
process.stdout.write(JSON.stringify(result));
console.log(result)
process.exit(0)
}
process.stdin.on('data', async (data) => {
await processImage(data);
});
Python 子进程通信
在 Python 方面,有一个值得注意的尝试,将图像数据作为 JSON 字符串化数据发送。但是,如果您要恢复使用文件路径或需要处理二进制数据(如图像),则需要调整读取和发送此数据的方式。对于二进制数据,您不会在 Popen 调用中使用 text=True,因为这表明您正在处理文本数据。相反,将数据作为二进制处理,并确保 JavaScript 端已准备好这种格式。
如果坚持使用临时文件方法:
确保图像文件 (photo1.png) 存在并且可由 Node.js 脚本访问。 考虑在调用子进程之前在 Python 中显式等待文件写入完成。
在数据传递方法(文件路径与直接数据)之间切换需要仔细处理两端的数据。如果直接数据传输太麻烦,使用临时文件可能是一种更可靠但效率较低的方法。始终确保您的异步 JavaScript 代码正确地发出完成信号,尤其是从 Python 调用时。