I'm developing an application in node.js (Loopback 4) that's downloads an image into a folder then gets the feature vector of this image, but i'm getting this error.
PythonShellError: cv2.error: OpenCV(4.4.0) /tmp/pip-req-build-b_zf9wbm/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
at PythonShell.parseError (/home/lucas/Dev/card-game-catalog/node_modules/python-shell/index.ts:332:21)
at terminateIfNeeded (/home/lucas/Dev/card-game-catalog/node_modules/python-shell/index.ts:190:32)
at ChildProcess.<anonymous> (/home/lucas/Dev/card-game-catalog/node_modules/python-shell/index.ts:181:13)
at ChildProcess.emit (events.js:315:20)
at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
----- Python Traceback -----
File "/home/lucas/Dev/card-game-catalog/src/utils/cardFeatureExtraction/index.py", line 18, in <module>
features = cd.describe(image)
File "/home/lucas/Dev/card-game-catalog/src/utils/cardFeatureExtraction/pyimagesearch/colordescriptor.py", line 14, in describe
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) {
traceback: 'Traceback (most recent call last):\n' +
' File "/home/lucas/Dev/card-game-catalog/src/utils/cardFeatureExtraction/index.py", line 18, in <module>\n' +
' features = cd.describe(image)\n' +
' File "/home/lucas/Dev/card-game-catalog/src/utils/cardFeatureExtraction/pyimagesearch/colordescriptor.py", line 14, in describe\n' +
' image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)\n' +
"cv2.error: OpenCV(4.4.0) /tmp/pip-req-build-b_zf9wbm/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'\n" +
'\n',
executable: 'python3',
options: [ '-u' ],
script: '/home/lucas/Dev/card-game-catalog/src/utils/cardFeatureExtraction/index.py',
args: [
'--dataset',
'dataset',
'--image',
'145fb3f3-48a4-5157-b5e2-db597ffe8231_art_crop.png'
],
exitCode: 1
}
To be able to get the feature vector of the image the application runs a python script inside my node application using python-shell. Before running the python script, the application checks if the images exists, then runs the python script. If i run the python script into a terminal, the error doesn't occurs, but when running inside python-shell it doesn't find the image file returning the error.
This is my python script(index.py)
# import the necessary packages
from pyimagesearch.colordescriptor import ColorDescriptor
import argparse
import glob
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required = True,
help = "Path to the directory that contains the images to be indexed")
ap.add_argument("-img", "--image", required = True,
help = "Image to be indexed")
args = vars(ap.parse_args())
# initialize the color descriptor
cd = ColorDescriptor((8, 12, 3))
imageID = args["image"]
image = cv2.imread(args["dataset"] + "/" + args["image"])
# describe the image
features = cd.describe(image)
# write the features to file
features = [str(f) for f in features]
print('[' + ','.join(features) + ']')
This is the colordescriptor.py
# import the necessary packages
import numpy as np
import cv2
import imutils
class ColorDescriptor:
def __init__(self, bins):
# store the number of bins for the 3D histogram
self.bins = bins
def describe(self, image):
# convert the image to the HSV color space and initialize
# the features used to quantify the image
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
features = []
# grab the dimensions and compute the center of the image
(h, w) = image.shape[:2]
(cX, cY) = (int(w * 0.5), int(h * 0.5))
# divide the image into four rectangles/segments (top-left,
# top-right, bottom-right, bottom-left)
segments = [(0, cX, 0, cY), (cX, w, 0, cY), (cX, w, cY, h),
(0, cX, cY, h)]
# construct an elliptical mask representing the center of the
# image
(axesX, axesY) = (int(w * 0.75) // 2, int(h * 0.75) // 2)
ellipMask = np.zeros(image.shape[:2], dtype = "uint8")
cv2.ellipse(ellipMask, (cX, cY), (axesX, axesY), 0, 0, 360, 255, -1)
# loop over the segments
for (startX, endX, startY, endY) in segments:
# construct a mask for each corner of the image, subtracting
# the elliptical center from it
cornerMask = np.zeros(image.shape[:2], dtype = "uint8")
cv2.rectangle(cornerMask, (startX, startY), (endX, endY), 255, -1)
cornerMask = cv2.subtract(cornerMask, ellipMask)
# extract a color histogram from the image, then update the
# feature vector
hist = self.histogram(image, cornerMask)
features.extend(hist)
# extract a color histogram from the elliptical region and
# update the feature vector
hist = self.histogram(image, ellipMask)
features.extend(hist)
# return the feature vector
return features
def histogram(self, image, mask):
# extract a 3D color histogram from the masked region of the
# image, using the supplied number of bins per channel
hist = cv2.calcHist([image], [0, 1, 2], mask, self.bins,
[0, 180, 0, 256, 0, 256])
# normalize the histogram if we are using OpenCV 2.4
if imutils.is_cv2():
hist = cv2.normalize(hist).flatten()
# otherwise handle for OpenCV 3+
else:
hist = cv2.normalize(hist, hist).flatten()
# return the histogram
return hist
And this is my controller function (typescript)
async getCardFeatureVector(uuid: string): Promise<{success:boolean, error:Error, results:Array<number>}>{
let { PythonShell } = require('python-shell');
const fs = require('fs');
const imageName = `${uuid}_art_crop.png`;
const Path = require('path');
const scriptPath:string = Path.resolve(process.env.PYTHON_PATH || __dirname);
let options = {
mode: 'text',
pythonOptions: ['-u'],
args: ['--dataset', "dataset", '--image', imageName],
scriptPath: scriptPath,
};
let error: Error;
const path = Path.resolve(process.env.PYTHON_PATH || __dirname) + `/dataset/${imageName}`;
return new Promise (async (resolve, reject) => {
if (fs.existsSync(path)) {
const { success, err = '', results } = await new Promise((resolve, reject) => {
PythonShell.run('index.py', options, function (err: any, results: any) {
if (err) {
console.error(err);
reject({ success: false, err });
} else {
resolve({ success: true, results });
}
});
});
if (err != '') {
error = new Error(err);
}
if (success) {
resolve({success: true, error: error, results: (results && results.length > 0) ? results[0] : undefined });
} else {
reject({success: false, error: error, results: undefined});
}
} else {
error = new Error(`FILE DOESNT EXISTS - UUID: ${uuid}`);
reject({success: false, error: error, results: undefined});
}
});
}
My application folders is like this in case it's important:
└── card-game-catalog
├── index.js
├── index.ts
├── package.json
├── README.md
├── src
│ ├── controllers
│ └── utils
│ ├── cardFeatureExtraction
│ │ ├── dataset
│ │ │ ├── 145fb3f3-48a4-5157-b5e2-db597ffe8231_art_crop.png
│ │ ├── index.py
│ │ ├── pyimagesearch
│ │ ├── queries
│ │ └── search.py
EDIT
Recently I've been trying to execute the same python file using a child_process (exec) and my function became like this.
async getCardFeatureVector(uuid: string): Promise<{success:boolean, error:Error, results:Array<number>}>{
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const fs = require('fs');
const imageName = `${uuid}_art_crop.png`;
const Path = require('path');
let error: Error;
const path = Path.resolve(process.env.PYTHON_PATH || __dirname) + `/dataset/${imageName}`;
return new Promise (async (resolve, reject) => {
if (fs.existsSync(path)) {
const { success, err = '', results } = await new Promise((resolve, reject) => {
const { stdout, stderr } = await exec('python3 /home/lucas/Dev/CardFeatureExtraction/index.py --dataset /home/lucas/Dev/CardFeatureExtraction/dataset --image 145fb3f3-48a4-5157-b5e2-db597ffe8231_art_crop.png');
if (stderr) {
console.log(stderr);
reject({success: false, stderr});
}
});
if (err != '') {
error = new Error(err);
}
if (success) {
resolve({success: true, error: error, results: (results && results.length > 0) ? results[0] : undefined });
} else {
reject({success: false, error: error, results: undefined});
}
} else {
error = new Error(`FILE DOESNT EXISTS - UUID: ${uuid}`);
reject({success: false, error: error, results: undefined});
}
});
}
But unfortunately the error continues. If I change the command executed by the child_process to:
const { stdout, stderr } = await exec('ls /home/lucas/Dev/CardFeatureExtraction/dataset/145fb3f3-48a4-5157-b5e2-db597ffe8231_art_crop.png');
I'm able to see that the image is present into the folder.