OpenCV.js - detectMultiScale "This Exception cannot be caught" - javascript

I'm trying to use facial recognition via OpenCV.js, however when I call on the detectMultiScale() method of the CascadeClassifier object I receive the error:
Uncaught 6446128 - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.
The problem is I'm leveraging a hosted version of opencv.js directly from opencv.org - it's not a build version because I'm unable to build it myself, and therefore cannot follow the error's instructions.
I've followed an example from their GitHub here and adapted the code to suit my needs, as follows:
<html>
<head>
<script src="https://docs.opencv.org/master/opencv.js"></script>
<script src="https://docs.opencv.org/master/utils.js"></script>
</head>
<body>
<img id="test" src="image/with/face.jpg" alt=""/>
<canvas id="output"></canvas>
<script>
let face_cascade = new cv.CascadeClassifier();
face_cascade.load("https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades_cuda/haarcascade_frontalface_default.xml");
function face_detector() {
let imgEl = document.getElementById("test");
let img = cv.imread(imgEl);
cv.imshow("output", img);
let src = cv.imread("output");
let gray = new cv.Mat();
let msize = new cv.Size(0,0);
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
let faces = new cv.RectVector();
face_cascade.detectMultiScale(gray, faces, 1.1, 3, 0, msize, msize); //Error occurs here
}
face_detector();
</script>
</body>
</html>
Anyone with experience with OpenCV.js and facial recognition that could help?

Following this thread:
The xml files are "pre-built" before loading them with the load function. To achieve this it's used the function createFileFromUrl from utils.js. After that we can finally load our classifier from file.
let classifier = new cv.CascadeClassifier(); // initialize classifier
let utils = new Utils('errorMessage'); //use utils class
let faceCascadeFile = 'haarcascade_frontalface_default.xml'; // path to xml
// use createFileFromUrl to "pre-build" the xml
utils.createFileFromUrl(faceCascadeFile, faceCascadeFile, () => {
classifier.load(faceCascadeFile); // in the callback, load the cascade from file
});
Face Detection Other Example
TRY IT :
let src = cv.imread('canvasInput');
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
let faces = new cv.RectVector();
let eyes = new cv.RectVector();
let faceCascade = new cv.CascadeClassifier();
// load pre-trained classifiers
faceCascade.load('haarcascade_frontalface_default.xml');
// detect faces
let msize = new cv.Size(0, 0);
// try to change scaleFactor and minNeighbors values
faceCascade.detectMultiScale(gray, faces,1.05,0);
for (let i = 0; i < faces.size(); ++i) {
let roiGray = gray.roi(faces.get(i));
let roiSrc = src.roi(faces.get(i));
let point1 = new cv.Point(faces.get(i).x, faces.get(i).y);
let point2 = new cv.Point(faces.get(i).x + faces.get(i).width,
faces.get(i).y + faces.get(i).height);
cv.rectangle(src, point1, point2, [255, 0, 0, 255]);
roiGray.delete(); roiSrc.delete();
}
cv.imshow('canvasOutput', src);
src.delete(); gray.delete(); faceCascade.delete();
faces.delete(); eyes.delete();
Try to change faceCascade.detectMultiScale parameters like given examples below:
faceCascade.detectMultiScale(gray, faces,1.05,0);
faceCascade.detectMultiScale(gray, faces,1.05,1);
faceCascade.detectMultiScale(gray, faces,2,0);
faceCascade.detectMultiScale(gray, faces,2,1);
faceCascade.detectMultiScale(gray, faces,3,0);
faceCascade.detectMultiScale(gray, faces,3,1);
faceCascade.detectMultiScale(gray, faces,4,0);
faceCascade.detectMultiScale(gray, faces,4,1);

The solution is
let faceCascadeFile = 'haarcascade_frontalface_default.xml';
utils.createFileFromUrl(faceCascadeFile, faceCascadeFile, () => {
console.log('cascade ready to load.');
let src = cv.imread('imageInit');
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
let faces = new cv.RectVector();
let faceCascade = new cv.CascadeClassifier();
faceCascade.load(faceCascadeFile);
let msize = new cv.Size(0, 0);
faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, msize, msize);
});
}
For full code and explanation use this link Face Detection with Javascript and OpenCV
or
Human Eye Detection using Javascript and OpenCV

Related

opencvjs - convert python to javascript

I am trying to convert the following python code using opencv for image processing into javascript using opencvjs, but seem to be missing something as the output is not quite the same.
Would be great if someone could help me out here as the docs for opencvjs are few and far between.
python code:
img = cv.imread(inPath)
frame_HSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
frame_mask = cv.inRange(frame_HSV, (30, 50, 0), (80, 255, 255))
frame_mask = cv.bitwise_not(frame_mask)
frame_result = cv.bitwise_and(img, img, mask = frame_mask)
cv.imwrite(outPath, frame_result)
My javascript code:
const src = cv.imread('canvasInput');
const dst = new cv.Mat();
const hsv = new cv.Mat();
const hsvMask = new cv.Mat();
const hsvMaskInv = new cv.Mat();
cv.cvtColor(src, hsv, cv.COLOR_BGR2HSV, 0);
const low = new cv.Mat(hsv.rows, hsv.cols, hsv.type(), [30, 50, 0, 0]);
const high = new cv.Mat(hsv.rows, hsv.cols, hsv.type(), [80, 255, 255, 255]);
cv.inRange(hsv, low, high, hsvMask);
cv.bitwise_not(hsvMask, hsvMaskInv);
cv.bitwise_and(src, src, dst, hsvMaskInv);
cv.imshow('canvasOutput', dst);
src.delete();
dst.delete();
low.delete();
high.delete();
hsv.delete();
hsvMask.delete();
hsvMaskInv.delete();
The original image:
What python outputs:
What my javascript outputs:
TL;DR
Try replacing COLOR_BGR2HSV with cv.COLOR_RGB2HSV.
Implementation
Comparing opencv-python 4.5.3.56 with opencv.js 3.4.0, the image being read had the green and red channels swapped.
A direct translation of your python code would look like this:
// img = cv.imread(inPath)
let img = cv.imread(imgElement);
// frame_HSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
let frameHSV = new cv.Mat();
cv.cvtColor(img, frameHSV, cv.COLOR_RGB2HSV, 0);
// frame_mask = cv.inRange(frame_HSV, (30, 50, 0), (80, 255, 255))
let frameMask = new cv.Mat();
let low = new cv.Mat(frameHSV.rows, frameHSV.cols, frameHSV.type(), [30, 50, 0, 0]);
let high = new cv.Mat(frameHSV.rows, frameHSV.cols, frameHSV.type(), [80, 255, 255, 255]);
cv.inRange(frameHSV, low, high, frameMask);
// frame_mask = cv.bitwise_not(frame_mask)
cv.bitwise_not(frameMask, frameMask);
// frame_result = cv.bitwise_and(img, img, mask = frame_mask)
let frameResult = new cv.Mat();
cv.bitwise_and(img, img, frameResult, frameMask);
// cv.imwrite(outPath, frame_result)
cv.imshow('canvasOutput', frameResult);
img.delete(); frameHSV.delete(); frameMask.delete();
low.delete(); high.delete(); frameResult.delete();
Debug Method
You could try logging the images as matrices, so the swapped channels would be easily spotted, but I resorted to furas' suggestion above: display the results after every modification. Here are the results of your Python code and your JavaScript code, respectively:

Can't figure out why opencv.js cv.fitEllipse() triggers uncaught exception with 1 image but not another

I have this function that simply crops the background from a picture of a coin and mostly works.
but for some reason "cv.fitEllipse" gives me an uncaught exception with this image:
bad image
but works fine with this image:
good image
I'm at a loss. any ideas? The size of the image that doesn't work is larger but that is the only thing I can figure out.
any ideas?
Ellipse_img = function(el) {
let src = cv.imread('imageChangeup');
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_BGR2GRAY);
let dst = new cv.Mat();
cv.threshold(gray, dst, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1];
// apply morphology open and close
let morph = new cv.Mat();
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, new cv.Size(5,5));
cv.morphologyEx(dst, morph, cv.MORPH_OPEN, kernel);
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, new cv.Size(21,21));
cv.morphologyEx(morph, morph, cv.MORPH_CLOSE, kernel);
//find all the contours
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(morph, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE);
//find largest contour
let area_max =0;
let i_max = 0;
let cnt_max = 0;
for (let i = 0; i < contours.size(); i++) {
let cnt = contours.get(i);
let area = cv.contourArea(cnt, false);
if(area >= area_max){
area_max = area;
i_max = i;
cnt_max = cnt;
}
}
let rotatedRect = cv.fitEllipse(cnt_max); //<<<<<<<<<<<<THE PROBLEM???
let ellipseColor = new cv.Scalar(255, 255, 255, 255);
let ellipseColor2 = new cv.Scalar(255, 255, 255, 255);
cv.ellipse1(src, rotatedRect, ellipseColor, 3, cv.LINE_8);
let mask = new cv.Mat.ones(src.size(), cv.CV_8UC3);
cv.ellipse1(mask, rotatedRect, ellipseColor2, -1, cv.LINE_8);
cv.cvtColor(mask, mask, cv.COLOR_BGR2GRAY);
cv.bitwise_and(src, src, dst, mask);
cv.imshow('imageChangeup', dst);
src.delete();
dst.delete();
gray.delete();
morph.delete();
contours.delete();
hierarchy.delete();
};
here is high level of cnt_max for good and bad -- must not be finding the circle but why?
cnt_max: data32S: Int32Array(2426)
cnt_max: data32S: Int32Array(8)
I'm far from knowledgeable enough to know why... but.. this had to do with the white around the object in the 'good' picture and the THRESH used.
This worked if I changed thresholds based on background
cv.threshold(gray, dst, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]; //for light backgrounds
cv.threshold(gray, dst, 0, 255, cv.THRESH_OTSU)[1]; //for dark backgrounds
so I changed to adaptiveThreshold and it seems to work for all scenarios
cv.adaptiveThreshold(gray, dst, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY_INV,11,2)

Smooth foreground extraction

I am trying to do smooth foreground extraction couple of days.I tried many things but nothing seems to work ;( ;(
I just want smooth human body extraction just like this:https://www.youtube.com/watch?v=rGMqXBvYxog
1-)I use Morphological Transformations and BackgroundSubstraction to do this.
Documentation says
"Opening for removing background noise and closing image for closing small holes inside the foreground objects" But It didn't work ;(
Without Closing and Opening : https://streamable.com/xh368
With Closing and Opening : https://streamable.com/bixmm
Closing and Opening Javascript Code :
let video = document.getElementById('videoInput');
let cap = new cv.VideoCapture(video);
let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1);
let fgbg = new cv.BackgroundSubtractorMOG2(500, 16,false);
const FPS = 30;
function processVideo() {
try {
if (!streaming) {
// clean and stop.
frame.delete(); fgmask.delete(); fgbg.delete();
return;
}
let begin = Date.now();
// start processing.
cap.read(frame);
fgbg.apply(frame, fgmask); //Apply Background Substraction
cv.bitwise_not(fgmask,fgmask);//Set background color black and foreground color white for Morphological Transformations
let M = cv.Mat.ones(5,5, cv.CV_8U);
let anchor = new cv.Point(-1, -1);
cv.morphologyEx(fgmask, fgmask, cv.MORPH_OPEN, M, anchor, 1,
cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue());
cv.morphologyEx(fgmask,fgmask, cv.MORPH_CLOSE, M);
frame.copyTo(fgmask, fgmask); //Copy original colors
cv.imshow('canvasOutput', fgmask);
// schedule the next one.
let delay = 100/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
utils.printError(err);
}
};
// schedule the first one.
setTimeout(processVideo, 0);
Full HTML:https://anotepad.com/notes/ne7n4w
All files:https://files.fm/u/c9egsgqe
2-))I am using haarcascades to extract human bodies in this technique , just like this:https://www.bytefish.de/blog/extracting_contours_with_opencv/
This algorithm run on following 5 steps.These algorithm not work very well because sometimes haar cascades cannot detect objects
Javascript Code
let src = cv.imread('canvasInput');
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
let faces = new cv.RectVector();
let poly=new cv.MatVector();
let faceCascade = new cv.CascadeClassifier();
faceCascade.load('haarcascade_frontalface_default.xml');
let msize = new cv.Size(0, 0);
faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, msize, msize);
//1-Create a mask with the rectangular coordinates
let rect = new cv.Rect(faces.get(0).x, faces.get(0).y,faces.get(0).width,faces.get(0).height);
//2-Mask out
dst = src.roi(rect);
//3-Edge detection using canny
let cannyoutput=new cv.Mat();
cv.Canny(dst, cannyoutput, 0, 100, 3, true);
//4-Find contours
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(cannyoutput,contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_NONE);
//cv.drawContours();
cv.imshow('canvasOutput', cannyoutput);
src.delete(); gray.delete(); faceCascade.delete();
faces.delete();
contours.delete(); hierarchy.delete();
3-)I tried to apply erosion then dialatios ,it didn't work.This Answer
Without Erosion And Dilation : https://streamable.com/xh368
With Erosion And Dilation : https://streamable.com/fffsn
My javascript code:
let video = document.getElementById('videoInput');
let cap = new cv.VideoCapture(video);
let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1);
let fgbg = new cv.BackgroundSubtractorMOG2(500, 16,false);
const FPS = 30;
function processVideo() {
try {
if (!streaming) {
// clean and stop.
frame.delete(); fgmask.delete(); fgbg.delete();
return;
}
let begin = Date.now();
// start processing.
cap.read(frame);
fgbg.apply(frame, fgmask);
cv.bitwise_not(fgmask,fgmask);
let M = cv.Mat.ones(5,5, cv.CV_8U);
let anchor = new cv.Point(-1, -1);
cv.erode(fgmask, fgmask, M, anchor, 1,
cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue());
cv.dilate(fgmask, fgmask, M, anchor, 1, cv.BORDER_CONSTANT,
cv.morphologyDefaultBorderValue());
frame.copyTo(fgmask, fgmask);
cv.imshow('canvasOutput', fgmask);
// schedule the next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
utils.printError(err);
}
};
// schedule the first one.
setTimeout(processVideo, 0);
My full html:https://anotepad.com/notes/gg5esk

How to create a mask in OpenCV.js?

I can create a mask in OPENCV C++ using cv::Mat::zeros and Rect.But i cannot find these features on OPENCV.js.How can i create a mask on OPENCV.js?
cv::Mat mask = cv::Mat::zeros(8, 8, CV_8U); // all 0
mask(Rect(2,2,4,4)) = 1;
let src = cv.imread('canvasInput');
let dst = new cv.Mat();
// You can try more different parameters
let rect = new cv.Rect(100, 100, 200, 200);
dst = src.roi(rect);
cv.imshow('canvasOutput', dst);
src.delete();
dst.delete();
Taken from here, specifically the Image ROI section

Loading Blender scene in BabylonJS

I made a scene in Blender that I exported into a .babylon, and now I am importing it into the game. The map is 351KB, and I am loading it into the game like this:
var BABYLON;
var canvas = document.getElementById('gamecanvas');
var engine = new BABYLON.Engine(canvas, true);
var scene = new BABYLON.Scene(engine);
var light = new BABYLON.PointLight('light', new BABYLON.Vector3(0,0,10), scene);
var player = new BABYLON.FreeCamera('player', new BABYLON.Vector3(1,1,1), scene); //IMPORTANT LINE
var player_height = 2;
var player_speed = 1;
var player_inertia = 0.9;
var mouse_position = new BABYLON.Vector2(mouse_position.x, mouse_position.y);
function INIT_GAME(){
engine.runRenderLoop(function(){ //IMPORTANT LINE
scene.render();
});
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock;
canvas.requestPointerLock();
scene.enablePhysics(); //IMPORTANT LINE
scene.setGravity(new BABYLON.Vector3(0, -10, 0)); //IMPORTANT LINE
player.attachControl(canvas, true); //IMPORTANT LINE
player.ellipsoid = new BABYLON.Vector3(1, player_height, 1);
player.checkCollisions = true;
player.applyGravity = true;
player.keysUp = [87];
player.keysDown = [83];
player.keysLeft = [65];
player.keysRight = [68];
player.inertia = player_inertia;
player.speed = player_speed;
window.addEventListener('resize', function(){
engine.resize();
});
BABYLON.SceneLoader.Load('Scenes', 'zombie_map.babylon', engine); //IMPORTANT LINE
}
I've attempted to narrow everything down to what you should need to look at, but I left it all there just in case there was something I missed. (INIT_GAME is loaded on page load). My problem is, I think the scene is loading, but it just gives me a strange loading icon, which I presume is just Babylon trying to load in the scene I passed it. My questions are:
Am I loading everything in properly?
What is the proper format to import a .babylon scene?
Is the size of the map too big for the browser, and if so, how can I compress it?
I can provide a link to the site if you need to see the results head-on. Let me know, thanks!
I think the solution is very simple.
Add a slash after your rootURL.
So replace
BABYLON.SceneLoader.Load('Scenes', 'zombie_map.babylon', engine); //IMPORTANT LINE
with
BABYLON.SceneLoader.Load('Scenes/', 'zombie_map.babylon', engine); //IMPORTANT LINE
Try this and let me know how it goes.

Categories