1

I am trying to obtain the value of category variable using a machine learning code in python. Although when i execute the code the category variable isn't changed at all and database stores the category as "A" which is defined outside globally. As far as i know, it is due to some asynchronous behavior but i don't know the actual solution.

var category = "A";
if (type == "lost") {
  var spawn = require("child_process").spawn;
  var process = spawn('python', ["./evaluate_lost.py", req.body.image]);
  process.stdout.on('data', function(data) {
    category += data.toString();
  });
  var newLost = {
    name: name,
    date: date,
    time: time,
    location: location,
    phone: phone,
    image: image,
    description: desc,
    category: category,
    author: author
  };
  // Create a new lost and save to DB
  Lost.create(newLost, function(err, newlyCreated) {
    if (err) {
      console.log(err);
    } else {
      //redirect back to items page
      res.redirect("/items");
    }
  });
}

Well i am editing the question with the evaluate_lost.py script and the directory structure.

import sys
from keras import backend as K
import inception_v4
import numpy as np
import cv2
import os
import argparse

image=sys.argv[1]


# If you want to use a GPU set its index here
os.environ['CUDA_VISIBLE_DEVICES'] = ''


# This function comes from Google's ImageNet Preprocessing Script
def central_crop(image, central_fraction):
    if central_fraction <= 0.0 or central_fraction > 1.0:
        raise ValueError('central_fraction must be within (0, 1]')
    if central_fraction == 1.0:
        return image

    img_shape = image.shape
    depth = img_shape[2]
    fraction_offset = int(1 / ((1 - central_fraction) / 2.0))
    bbox_h_start = int(np.divide(img_shape[0], fraction_offset))
    bbox_w_start = int(np.divide(img_shape[1], fraction_offset))

    bbox_h_size = int(img_shape[0] - bbox_h_start * 2)
    bbox_w_size = int(img_shape[1] - bbox_w_start * 2)

    image = image[bbox_h_start:bbox_h_start+bbox_h_size, bbox_w_start:bbox_w_start+bbox_w_size]
    return image


def get_processed_image(img_path):
    # Load image and convert from BGR to RGB
    im = np.asarray(cv2.imread(img_path))[:,:,::-1]
    im = central_crop(im, 0.875)
    im = cv2.resize(im, (299, 299))
    im = inception_v4.preprocess_input(im)
    if K.image_data_format() == "channels_first":
        im = np.transpose(im, (2,0,1))
        im = im.reshape(-1,3,299,299)
    else:
        im = im.reshape(-1,299,299,3)
    return im


if __name__ == "__main__":
    # Create model and load pre-trained weights
    model = inception_v4.create_model(weights='imagenet', include_top=True)

    # Open Class labels dictionary. (human readable label given ID)
    classes = eval(open('validation_utils/class_names.txt', 'r').read())

    # Load test image!
    img_path = "../public/files/lost/" + image
    img = get_processed_image(img_path)

    # Run prediction on test image
    preds = model.predict(img)
    print("Class is: " + classes[np.argmax(preds)-1])
    print("Certainty is: " + str(preds[0][np.argmax(preds)]))
    sys.stdout.flush()

This is the directory structure which evaluates the python script on watch.jpg which is input through HTML form

I expect the category to be as returned from python machine learning code rather than what is already defined.

James Z
  • 12,209
  • 10
  • 24
  • 44

1 Answers1

0

The data event handler runs asynchronously, you're not waiting for all the output to be consumed.

Use the end event to detect the end of the output, and run the code that saves the new Lost object there.

var category = "A";
if (type == "lost") {
  var spawn = require("child_process").spawn;
  var process = spawn('python', ["./evaluate_lost.py", req.body.image]);
  process.stdout.on('data', function(data) {
    category += data.toString();
  });
  process.stdout.on('end', function() {
    var newLost = {
      name: name,
      date: date,
      time: time,
      location: location,
      phone: phone,
      image: image,
      description: desc,
      category: category,
      author: author
    };
    // Create a new lost and save to DB
    Lost.create(newLost, function(err, newlyCreated) {
      if (err) {
        console.log(err);
      } else {
        //redirect back to items page
        res.redirect("/items");
      }
    });
  });
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • I tried using the same method as you have suggested but it still saves the category as "A". – Navneet Kumar Apr 21 '19 at 10:23
  • Try adding `console.log` to the `data` handler to see if you're ever getting data from the python process. – Barmar Apr 21 '19 at 10:26
  • I am not sure why but console.log doesnt output anything either. – Navneet Kumar Apr 21 '19 at 10:44
  • Try checking for an error with `process.on("error", ...)` – Barmar Apr 21 '19 at 10:56
  • I have edited the question with the python script and the directory structure. The script is working fine and the problem is more or less about the right paths of files. I am not able to recognise the same and need assistance for same. Thanks for the help. – Navneet Kumar Apr 21 '19 at 11:01
  • See https://stackoverflow.com/questions/918154/relative-paths-in-python for how to parse pathnames relative to the directory containing the script. – Barmar Apr 21 '19 at 11:04
  • Now with the paths specified correctly, i am sure that the script is running in the background as it takes the required time until the record is saved but still the value of category remains the same. The problem still remains that the variable isnt changed globally. – Navneet Kumar Apr 21 '19 at 11:55
  • Are you seeing the console log messages? – Barmar Apr 21 '19 at 12:00
  • Nothing on console as of now. Even I tried console logging at the very start of Post Request and it outputs nothing. – Navneet Kumar Apr 21 '19 at 12:37