Ищете доступ к 16-битным данным изображения в Javascript / WebGL - PullRequest
7 голосов
/ 20 июня 2011

Я пытаюсь загрузить 16-битные данные изображения с сервера и вставить их в текстуру WebGL без плагинов для браузера.texImage2d будет работать с: ImageData, HTMLImageElement, HTMLCanvasElement или HTMLVideoElement.Я ищу какой-нибудь javascript (библиотека или пример кода), который может декодировать 16-битные данные изображения TIFF или аналогичные (hdf5 и т. Д.) В один из этих типов объектов.

У меня нет проблем с этимиспользует 8-битный RGB на канал, используя для загрузки PNG, но это не работает с 16-битными данными на канал, так как нет никаких «стандартных» поддерживаемых браузером форматов изображений, которые являются 16-битными.

Ответы [ 3 ]

4 голосов
/ 15 октября 2013

В случае объединения двух изображений PNG, одного с 8 старшими битами и второго с 8 младшими битами, я думаю, что это должно быть:

highp vec4 texCol = texture2D(tex_low, vec2(vTexCoord.s, vTexCoord.t)) * (1.0 / 257.0);
texCol += texture2D(tex_up, vec2(vTexCoord.s, vTexCoord.t)) * (256.0 / 257.0);

В 8 битах на канал цвета RGB будут варьироваться от 0 до 255 = 2 ^ 8 - 1.
В 16 битах на канал цвета RGB будут варьироваться от 0 до 65535 = 2 ^ 16 - 1 = 255 * 257.

Объяснение

WebGL работает с использованием значений цвета от 0 до 1 и делает это путем деления 8-битного значения цвета на 255. Таким образом, разделенное значение принадлежит диапазону <0,1>.
В случае 16 бит на канал мы хотели бы разделить его на 65535, чтобы получить правильное число из диапазона <0,1>.

Нам нужно 16-битное значение цвета, уменьшенное до диапазона <0,1>.
Пусть low и up будут значениями цвета из диапазона 0..255. up - это старшие 8 бит, а low - младшие 8 бит.
Чтобы получить 16-битное значение, мы можем вычислить: low + up*256. Теперь у нас есть номер в диапазоне 0..65535. Чтобы получить значение из диапазона <0,1>, мы делим его на 65535. Обратите внимание, что WebGL работает с использованием значений цвета из диапазона <0,1>, это Lw=low/255 и Uw=up/255. Таким образом, нам не нужно умножать его на 255 и делить на 65535, потому что 65535 = 255 * 257. Вместо этого мы просто делим на 257.

enter image description here

Также я не смог найти никакого программного обеспечения для разделения 16-битного / канального изображения на два 8-битных / канальных изображения, так что вот мой код, не стесняйтесь его использовать, он разбивает 16-битный / канальный Tiff на два 8-битных / канальных PNGs:

https://github.com/czero69/ImageSplitter

4 голосов
/ 31 июля 2011

Я не думаю, что в настоящее время основные браузеры изначально поддерживают какой-либо 16-битный / канальный формат изображения.

Один из способов добиться того же эффекта - создать два изображения PNG, одно с верхним8 бит каждого цветового канала в изображении и один с нижними 8 битами.Затем свяжите изображения как две текстуры и объедините значения в вашем шейдере, например,

highp float val = texture2d(samplerTop8bits, tex_coord) * (256.0 / 257.0);
val += texture2d(samplerBottom8bits, tex_coord) * (1.0 / 257.0);

(Примечание: вам нужна высокая точность для правильного представления ваших данных в 16-битном диапазоне)

Другой метод возможен только в том случае, если в целевом браузере поддерживаются текстуры с плавающей точкой.Вы бы в браузере объединили два PNG-изображения в текстуру с плавающей точкой, а затем получили к ней доступ.Это может быть не так быстро и, вероятно, будет использовать вдвое больше памяти для текстур.

2 голосов
/ 21 июня 2015

PNGToy - это отличная библиотека для извлечения фрагментов PNG практически всех глубин и режимов каналов с помощью javascript (действительно на стороне клиента / без node.js, только зависимости Promise.js).Метод декодирования вернет нужный буфер.Вот пример для 16-битного PNG в градациях серого (16-битный RGB также должен работать):

var dataObj;
var img = new PngImage();
var buffer;

img.onload = function() {

    var pngtoy = this.pngtoy;

    dataObj = pngtoy.decode().then(function(results) {

        buffer = new Uint16Array(results.bitmap);

        for(var i = 0, j; i < buffer.length; i++) {

          j = buffer[i];
          buffer[i] = ((j & 0xff) << 8) | ((j & 0xff00) >>> 8); // needed to swap bytes for correct unsigned integer values  
        }

        console.log(buffer);
    });     
};

img.onerror = function(e) {
    console.log(e.message);
};

img.src = "image.png";
...