How to create a mask in OpenCV.js? - javascript

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

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:

TensorflowJs - Rescale image with factor

Is it possible to achieve the same Python operation in Javascript using TensorflowJs?
from tensorflow.keras.preprocessing.image import ImageDataGenerator
test_datagen = ImageDataGenerator(rescale=1./255) # NOTE: Re-scaling operation as part of the pre-processing step
I am trying to run a custom model in the browser, but it requires this preprocessing step before I can feed it to tensorflowjs. It requires I rescale the image by a factor of 1/255.
Any idea how I could achieve this?
I can't find anything with tersorflowjs, so decided to try with opencvjs, but I am not too sure this has the same effect:
function rescaleImg(img, canvasId) {
const src = cv.imread(img);
let dst = new cv.Mat();
let dsize = new cv.Size(
parseFloat((src.rows * (1 / 255)) / 100),
parseFloat((src.cols * (1 / 255)) / 100)
);
cv.resize(src, dst, dsize, 1 / 255, 1 / 255, cv.INTER_AREA);
cv.imshow(canvasId, dst);
src.delete();
dst.delete();
}
I then pass the image to tensorflowjs like:
const shapeX = 150;
const shapeY = 150;
rescaleImg(image, id);
const canvas = document.getElementById(id);
tensor = tf.browser
.fromPixels(canvas)
.resizeNearestNeighbor([shapeX, shapeY])
.expandDims(0)
.toFloat();
}
const prediction = await model.predict(tensor).data();
"rescale" and "resize" are two different operations.
"rescale" modifies the pixel value, while "resize" modify the image size (yeah, also pixel value because of interpolation, but it's just a side effect).
To "rescale" the image in OpenCV you use convertTo with the optional scaling factor.
Also, when you rescale, you need to be sure to use the correct underlying data type to hold the new values.
Something like this should work:
const src = cv.imread(img);
let dst = new cv.Mat();
// rescale by 1/255, and hold values in a matrix with float32 data type
src.convertTo(dst, cv.CV_32F, 1./255.);
cv.imshow(canvasId, dst);
So far I have settle with having the following, using opencvJs:
function rescaleImg(img, canvasId) {
try {
const src = cv.imread(img);
let dst = new cv.Mat();
let dsize = new cv.Size(src.rows, src.cols);
cv.resize(src, dst, dsize, 1 / 255, 1 / 255, cv.INTER_AREA);
cv.imshow(canvasId, dst);
src.delete();
dst.delete();
} catch (e) {
console.log("Error running resize ", e);
throw e;
}
}

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)

Im trying to detect circle only at real-time webcam, and draw circle on it

I trying to detect circle only on real-time webcam video and trying to draw circle border on my targeted circle, but right now I can draw a circle on output on a random target, please help me to get the circle target. I'm developing this code in javascript and using opencv.js. That random detection also detecting on video bottom only not in any other places.
function processVideo() {
try {
if (!streaming) {
// clean and stop.
src.delete();
dst.delete();
dstC1.delete();
dstC3.delete();
return;
}
let begin = Date.now();
// start processing.
cap.read(src);
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);
cv.blur(dst, dstC1, ksize, anchor, cv.BORDER_DEFAULT); // blur the image to avoids noise
cv.Canny(dstC1, dstC1, 50, 100, 3, false); // black and white border
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(dstC1, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE, offset = new cv.Point(0, 0));
let cnt = contours.get(0);
let contoursColor = new cv.Scalar(255, 255, 255);
let circleColor = new cv.Scalar(255, 0, 0);
let circle = cv.minEnclosingCircle(cnt);// this one for circle
cv.drawContours(dstC1, contours, 0, contoursColor, 1, 8, hierarchy, 100);
for (let i = 0; i < 4; i++) {
cv.circle(dstC1, circle.center, circle.radius, circleColor, 3);
}
cv.imshow('canvasOutput', dstC1);
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
utils.printError(err);
}
};

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

Categories