Remy Mellet
Remy Mellet

Reputation: 1795

How to load 16 bits grayscale png in OpenCV.js?

I want to load a 16 bit grayscale PNG in Javascript (where each pixel represent a number/depth value. This is file format is used by TUM to store depth information)

However, the image read by opencv.js is RGBA 8bits (mat.type() == 24 == cv.CV_8UC4 - and I would like to get cv.CV_16UC1), which seems to be because the image is decode by the browser itself and Because canvas only support 8-bit RGBA image with continuous storage, the cv.Mat type is cv.CV_8UC4 as the documentation indicates it. Thus instead of getting a pixel we a value between 0 and 65535 (2^8-1) I get a number between 0 and 255 (2^8-1) with R=G=B and A=255

[Edit] To reformulate it, canvas convert my 16bit grayscale to 8bit RGBA. Canvas handle 2^24 colors but as during the conversion R=G=B and each channel is 2^8, thus it handle only 2^8 grays instead of 2^16 grays.

Nothing special is done : https://jsfiddle.net/remmel/rmntq4yb/74/

Extract:

var img = await loadImage("https://raw.githubusercontent.com/remmel/rgbd-dataset/main/rgbd_dataset_freiburg1_desk/depth/1305031468.188327.png");
var canvasOriginal = document.getElementById('canvas0')
var ctxOriginal = canvasOriginal.getContext('2d')
canvasOriginal.width = img.width
canvasOriginal.height = img.height
ctxOriginal.drawImage(img, 0, 0)
var mat = cv.imread('canvas0')
console.log(mat.channels(), mat.type() === cv.CV_8UC4) //4, true

Image magick:

$ identify 1305031468.188327.png
1305031468.188327.png PNG 640x480 640x480+0+0 16-bit Grayscale Gray 131604B 0.000u 0:00.000

I tried to decoded the image using jimp-browser, but still get a RGBA image. Debugging it, I see that it read the correct gray value in 16bit but after convert it in 8bit with R=G=B=gray 8bit and A=255. A solution could be to custom (fix?) that lib

I also tried loading directly the image with OpenCV.js, but still the same 4 channels image :

<img src='https://i.sstatic.net/8am9t.png' id='dpng' />

  var depthMat2 = cv.imread('dpng')
  console.log(depthMat2.channels(), depthMat2.type() === cv.CV_8UC4) //4 true

Image (imgur seems to not compress the image) : enter image description here

Upvotes: 2

Views: 1388

Answers (2)

Remy Mellet
Remy Mellet

Reputation: 1795

I used instead fast-png lib to read my 16 bits grayscale PNG : https://www.npmjs.com/package/fast-png

import { decode } from 'fast-png'
...
var arrayBuffer = await((await fetch(urlDepth)).arrayBuffer())
var depthData = (await decode(arrayBuffer)).data

Upvotes: 2

StackSlave
StackSlave

Reputation: 10627

I think you just want to do ratio math:

function rgbAlter(rgb){
  return 65535/255*rgb;
}
for(let i=0,l=256; i<l; i++){
  console.log(rgbAlter(i));
}

Upvotes: -2

Related Questions