Place an image over another image using OpenCV.js

Hello I have been struggling with OpenCV.js for a while now. Thanks to @berak I am closer to the solution now. I am trying to build a Javascript library using OpenCV.js which takes an image as input and provides an output image in which the human skin is blurred.

Right now my script looks like this

let src = cv.imread(imgElement);
let dst = new cv.Mat();
let dst_1 = new cv.Mat();

// converting from gbr to hsv color space
cv.cvtColor(src, dst, cv.COLOR_RGB2HSV)
cv.cvtColor(dst, dst, cv.COLOR_RGB2BGR)

let hsv_low = new cv.Mat(dst.rows, dst.cols, dst.type(), [60, 25, 0, 0]);
let hsv_high = new cv.Mat(dst.rows, dst.cols, dst.type(), [255, 170, 20, 0]);

// skin color range for hsv color space 
cv.inRange(dst, hsv_low, hsv_high, dst);

// converting from gbr to YCbCr color space
cv.cvtColor(src, dst_1, cv.COLOR_RGB2YCrCb);
cv.cvtColor(dst_1, dst_1, cv.COLOR_RGB2BGR);

let YCbCr_low = new cv.Mat(dst_1.rows, dst_1.cols, dst_1.type(), [90, 135, 10, 0]);
let YCbCr_high = new cv.Mat(dst_1.rows, dst_1.cols, dst_1.type(), [125, 175, 235, 0]);

// skin color range for YCbCr color space 
cv.inRange(dst_1, YCbCr_low, YCbCr_high, dst_1);

// merge skin detection (YCbCr and hsv)
cv.bitwise_and(dst_1, dst, dst)
cv.medianBlur(dst, dst, 3)

let ksize = new cv.Size(80, 80);
let anchor = new cv.Point(-1, -1);

// make blurred copy of original image
cv.blur(src, dst_1, ksize, anchor, cv.BORDER_DEFAULT);

let mask = dst.clone();

// mask blurred image to create image with only skin blurred, rest is opaque
dst_1.copyTo(dst, dst)

cv.imshow('canvasOutput', src);

src.delete();
dst.delete();
dst_1.delete();
hsv_low.delete();
hsv_high.delete();
YCbCr_low.delete();
YCbCr_high.delete();

I have successfully been able to create an image where skin part of the image is blurry and the rest of the image is transparent. Now the last step is to place this over the original image.

Screenshot 2021-09-28 at 1.04.48 PM

I have been trying to implement Bitwise Operations section of this doc, but I haven’t been successful. Any help will be appreciated.

Thank you.

The desired output is this
Screenshot 2021-09-28 at 3.34.09 PM

After trying to solve this problem for 2 days, I was able to solve this. The problem was solved by replacing the pixels of original image with the desired pixels from second image. This is the code

for (let i = 0; i < mask.rows; i++) {
    for (let j = 0; j < mask.cols; j++) {
        if (mask.ucharPtr(i, j)[0] === 255) {
            src.ucharPtr(i, j)[0] = dst.ucharPtr(i, j)[0]
            src.ucharPtr(i, j)[1] = dst.ucharPtr(i, j)[1]
            src.ucharPtr(i, j)[2] = dst.ucharPtr(i, j)[2]
            src.ucharPtr(i, j)[3] = dst.ucharPtr(i, j)[3]
        }
    }
}

Here, I have

  • src: Mat of original image
  • dst: Mat of image with skin part blurred and all other pixels transparent
  • mask: Original image’s mask with skin in white and other parts in black

Here is the result

Screenshot 2021-09-29 at 6.11.38 PM

this is exactly, what dst.setTo(src,mask); does ;]
(just much slower)