Home > Enterprise >  openCV Js add and subtract giving unexpected results
openCV Js add and subtract giving unexpected results

Time:10-01

I am using gaussianBlur to get the high pass of the image but it seems like cv.subtract() function does not subtract two images pixel by pixel. I confirmed this by first subtracting the blurred image from input image and then adding the blurred image again to the result. On doing so, the output should be the same as the input image but it is different.

    img=src
    cv.GaussianBlur(img, blur, new cv.Size(21, 21), 0,0,cv.BORDER_DEFAULT)
    let x = new cv.Mat()
    let y = new cv.Mat()
    cv.subtract(img,blur,x)
    cv.add(x,blur,y)

Here are the images for reference input image, blurred image, output image

CodePudding user response:

As commented, cv.add and cv.subtract functions clip the uint8 summed/subtracted elements to range [0, 255].
The solution is converting the mat data type from uint8 to larger data type as int16.


Example for clipping (pseudocode):
cv.add(uint8(200), uint8(100)) equals uint8(255) (instead of 300).
cv.subtract(uint8(10), uint8(20)) equals uint8(0) (instead of -10).

That means that computing: uint8(200) uint8(100) - uint8(100), results 155 (instead of getting back to the original value 200).

The solution is converting mat data type from uint8 to larger data type as int16.
int16 elements are clipped to range [-32768, 32767], and we are not getting close to these range limits.

Computing: int16(200) int16(100) - int16(100), results 200 (because int16(200) int16(100) = int16(300). No clipping occurs...


Converting from uint8 to int16 is performed using convertTo member function:

img.convertTo(img2, cv.CV_16S);
blur.convertTo(blur2, cv.CV_16S);

Then apply cv.subtract and cv.add to the int16 elements:

cv.subtract(img2, blur2, x)
cv.add(x, blur2, y)

At the end, we may convert the result back to uint8 type:

y.convertTo(out, cv.CV_8U);

Here is a sample that applies the above procedure, and verifies that out = img:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
</head>

<body>
<p id="status">OpenCV.js is loading...</p>
<div>
  <div >
    <img id="imageSrc" alt="No Image" />
    <div >imageSrc <input type="file" id="fileInput" name="file" /></div>
  </div>
  <div >
    <canvas id="canvasOutput" ></canvas>
    <div >canvasOutput</div>
  </div>
</div>

<script async src="opencv.js" type="text/javascript"></script>


<script type="text/javascript">
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
  imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);

//read image
imgElement.onload = function () {
  let img = cv.imread(imgElement);
  let blur = new cv.Mat();
  let x = new cv.Mat();
  let y = new cv.Mat();  
  let img2 = new cv.Mat();
  let blur2 = new cv.Mat();
  let out = new cv.Mat();
  
  cv.GaussianBlur(img, blur, new cv.Size(21, 21), 0, 0, cv.BORDER_DEFAULT);
  
  img.convertTo(img2, cv.CV_16S); //Convert img from type Uint8Array to type Int16Array
  blur.convertTo(blur2, cv.CV_16S); //Convert blur from type Uint8Array to type Int16Array
  
  cv.subtract(img2, blur2, x) //Subtract applies Int16 elements (instead of Uint8 elements).
  cv.add(x, blur2, y) //Add applies Int16 elements (instead of Uint8 elements).
  
  y.convertTo(out, cv.CV_8U); //Convert y from type Int16Array to type Uint8Array (out is used as input for imshow).
  cv.imshow('canvasOutput', out);
  
  
  let d = new cv.Mat();
  cv.absdiff(out, img, d);
   
  //Compute the sum of absolute difference (for testing)
  let sum_abs_dif = 0
  for (row = 0; row < d.rows; row  ) {
    for (col = 0; col < d.cols; col  ) {
      sum_abs_dif  = d.ucharPtr(row, col)[0]   d.ucharPtr(row, col)[1]   d.ucharPtr(row, col)[2];
      //d.ucharPtr(row, col)[3] = 255; //Set the alpha (transparency) channel to 255 for testing.
    }
  } 
 
  console.log(sum_abs_dif)  //Prints 0
  
  img.delete();
  blur.delete();
  x.delete();
  y.delete();
  img2.delete();
  blur2.delete();
  out.delete();
  d.delete();
};


//check openCV
var Module = {
  // https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
  onRuntimeInitialized() {
    document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
  }
};
</script>


</body>
</html>
  • Related