skip to Main Content

I am trying to start a javascript subprocess inside a python script.

I’d like to do some photo analysis, by using the Human repo, which doesn’t have any Python porting (natively js), so I must execute his detect function in javascript

The general idea is to start a Python code to take a picture from webcam (this is a project’s constraint) and then process the photo inside the js script.

(the best thing would be not to save the photo but to directly pass it to the js script, which I tried by frame_json = json.dumps(frame.tolist()) and then process.communicate(input=frame_json) but it didn’t work anyway)

This is my python code:

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()

whereas this is the 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();
});

The problem is that it seems like the Human library doesn’t execute, since I don’t see anything in my python output.
Obviously if I comment the Human section out and console.log('something') from the js, I am able to see it in my Python console.

I can’t figure out if is there something out that I’m missing.

Is there any concurrency problem? Or is there any chance that I’m using the library wrong in some way? (the library still works fine if used by itself without being used as subprocess, with node detect.js).

May someone give me an help?

2

Answers


  1. Chosen as BEST ANSWER

    EDIT: Eventually I managed to resolve my issue:

    Python code:

    import cv2
    import json
    import asyncio
    
    async def run_js_script(data):
    # Launch the subprocess
       proc = await asyncio.create_subprocess_exec('node', 'detect3.js', 
       stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE)
    
    # Send the data to the subprocess and get output
    
       output, _ = await proc.communicate(input=data.encode())
    
       return output.decode().strip()
    
    
    async def main():
        video_capture = cv2.VideoCapture(0)
    
        while True:
           # Grab a single frame of video
           ret, frame = video_capture.read()
    
           if not ret:
               break
    
           frame_json = json.dumps(frame.tolist())
    
           try:
               result = await run_js_script(frame_json)
               print(f'Result from JavaScript: {result}')
          except Exception as e:
               print(f'Error: {e}')
    
       
    
    asyncio.run(main())
    

    Javascript code:

    const human = new Human(config);
    
    async function processImage(data) {
    
       const frame1 = JSON.parse(data);
       
       const tensor = human.tf.tensor(frame1); 
       const result = await human.detect(tensor);
    
       return result["face"][0]["age"];
    }
    
    // Read input from stdin
    process.stdin.on('data', async (data) => {
       const result = await processImage(data);
    
       process.stdout.write(JSON.stringify(result));
       process.stdout.end();
      });
    

    The main issue was that the Python process was not waiting for Js to finish, so I made that async, forcing it to wait.

    Regarding the image processing, I decided to use a json as a bridge between these two codes, and using the tensor as human input, as its wiki suggests for some specific instances.


  2. Integrating JavaScript-based photo analysis into a Python project via subprocesses can be quite complex due to the intricacies of data passing and subprocess management. Your approach has a solid foundation, but there are a few key adjustments and considerations that could resolve the issues you’re facing.

    Data Passing Between Python and JavaScript

    Your current method attempts to pass the image file path directly as input to the subprocess, which seems a bit off from what you initially aimed for (passing the image data directly). Since direct data passing (as in image bytes or JSON representation) didn’t work as expected, using a temporary file to bridge the data between Python and JavaScript might be the most straightforward approach, albeit not the most efficient.

    However, to stick with your initial attempt at direct data passing, ensure your JavaScript script is correctly parsing the input data from Python. In your JavaScript code, you’re treating the input data as a file path (fs.readFileSync(inputFile);), which won’t work if you’re passing image data directly. You’d need to adjust this to handle raw image data if you want to avoid using an intermediate file.

    Handling Asynchronous JavaScript Code

    Your JavaScript function newFunction utilizes asynchronous code (human.detect(tensor, config).then(…)) but doesn’t properly handle this in the context of being called from Python. You need to ensure that your Node.js script correctly signals to the Python script when it’s done processing, especially when dealing with asynchronous operations.

    A quick fix is to use an async function wrapper in your JavaScript code and wait for the detect function to complete before writing to stdout and exiting:

    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 Subprocess Communication

    On the Python side, there’s a notable attempt to send image data as JSON stringified data. However, if you’re reverting to using file paths or need to handle binary data (like an image), you’ll need to adjust how you read and send this data. For binary data, you would not use text=True in your Popen call, as this indicates that you’re working with text data. Instead, handle the data as binary and ensure the JavaScript side is prepared for this format.

    If sticking with the temporary file method:

    Ensure the image file (photo1.png) exists and is accessible by the Node.js script.
    Consider explicitly waiting for the file write to complete in Python before invoking the subprocess.

    Switching between data passing methods (file paths vs. direct data) requires careful handling of the data on both ends. If direct data transfer proves too cumbersome, using temporary files might be a more reliable albeit less efficient method. Always ensure your asynchronous JavaScript code properly signals its completion, especially when invoked from Python.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search