javascript - start - opencv tutorial
¿Cómo usar LUT con JavaScript? (1)
Soy nuevo en el procesamiento de imágenes.
Quiero usar JavaScript para aplicar efectos a imágenes usando LUT (tablas de búsqueda) o los PNG de búsqueda correspondientes, algo como esto:
Busqué en Google y no pude encontrar un artículo o recurso que describa el proceso exacto de transformación de píxeles utilizando LUT.
He encontrado un buen artículo aquí , que describe las LUT 1D y 3D y las diferencias entre ellas. Pero todavía no está del todo claro para mí.
Quiero algo como esto , que se hace para iOS.
PD Por favor, no publique vínculos / respuestas sobre las bibliotecas de filtrado de imágenes, que están usando matrices de convolución para efectos o filtros.
Actualizar:
¡Finalmente! Tengo la respuesta gracias a @abbath. He creado una esencia en GitHub, que puedes encontrar aquí .
También soy nuevo en el tema, pero espero que ayude lo que he descubierto hasta ahora. Su imagen (la LUT) es una representación de una matriz 3D, imagine un cubo de 64x64x64. Esta representación está en 2D, un plano es un cuadrado de 64x64. Necesitas 64 piezas de este avión, por eso el png tiene 8x8 cuadrados. Si miras detenidamente, el cuadrado superior izquierdo tiene rojo (R de RGB) en el eje X y verde (G) en el eje Y. El azul (B) es el eje Z (lo imagino hacia arriba), que no se puede representar en 2D, por lo que aparece en los siguientes cuadros de 64x64. En el último cuadrado (abajo a la derecha) puede ver que es principalmente azul, donde las coordenadas rojas y verdes son 0.
Entonces, la siguiente pregunta es cómo proyectar una imagen con esta LUT. Lo probé en Java, en mi opinión, tendrá que perder cierta información porque 64x64x64 es mucho menos que 256x256x256, en este caso, debe dividir por 4 cada valor de color de píxel.
Los pasos:
- Iterate a través de los píxeles de tu imagen original. En una iteración, tendrá un píxel de la imagen original. Obtenga los valores R, G, B de ese píxel.
- Divida los valores por cuatro, por lo que tendrá un valor menor que 64.
- Obtenga el píxel correspondiente de su LUT, como si fuera un cubo de 64x64x64. Entonces, si RGB = (255,0,255) estaba en el pixel original, entonces divídalo para obtener (63,0,63), luego verifique el valor B, para obtener el cuadrado correspondiente en el png, que será el inferior derecho (en el caso de b = 63), y obtiene el r, g = (63,0) píxel, que se torna púrpura en tu imagen png.
Revisé Android, con código Java, es lo suficientemente rápido en mi opinión. Debajo está el código que he escrito, espero que sea suficiente para portarlo a javascript. (Espero que los comentarios sean suficientes para entender)
public Bitmap applyEffectToBitmap(Bitmap src, Bitmap lutbitmap) {
//android specific code, storing the LUT image''s pixels in an int array
int lutWidth = lutBitmap.getWidth();
int lutColors[] = new int[lutWidth * lutBitmap.getHeight()];
lutBitmap.getPixels(lutColors, 0, lutWidth, 0, 0, lutWidth, lutBitmap.getHeight());
//android specific code, storing the source image''s pixels in an int array
int srcWidth = src.getWidth();
int srcHeight = src.getHeight();
int[] pix = new int[srcWidth * srcHeight];
src.getPixels(pix, 0, srcWidth, 0, 0, srcWidth, srcHeight);
int R, G, B;
//now we can iterate through the pixels of the source image
for (int y = 0; y < srcHeight; y++){
for (int x = 0; x < srcWidth; x++) {
//index: because the pix[] is one dimensional
int index = y * srcWidth+ x;
//pix[index] returns a color, we need it''s r g b values, thats why the shift operator is used
int r = ((pix[index] >> 16) & 0xff) / 4;
int g = ((pix[index] >> 8) & 0xff) / 4;
int b = (pix[index] & 0xff) / 4;
//the magic happens here: the 3rd step above: blue pixel describes the
//column and row of which square you''ll need the pixel from
//then simply add the r and green value to get the coordinates
int lutX = (b % 8) * 64 + r;
int lutY = (b / 8) * 64 + g;
int lutIndex = lutY * lutWidth + lutX;
//same pixel getting as above, but now from the lutColors int array
R = ((lutColors[lutIndex] >> 16) & 0xff);
G = ((lutColors[lutIndex] >> 8) & 0xff);
B = ((lutColors[lutIndex]) & 0xff);
//overwrite pix array with the filtered values, alpha is 256 in my case, but you can use the original alpha
pix[index] = 0xff000000 | (R << 16) | (G << 8) | B;
}
}
//at the end of operations pix[] has the transformed pixels sou can set them to your new bitmap
//some android specific code is here for creating bitmaps
Bitmap result = Bitmap.createBitmap(srcWidth, srcHeight, src.getConfig());
result.setPixels(pix, 0, srcWidth, 0, 0, srcWidth, srcHeight);
return result ;
}
Ahora lo he implementado con éxito en javascript también, verifique el uso de las funciones Math.floor ():
for (var i=0;i<imgData.data.length;i+=4){
var r=Math.floor(imgData.data[i]/4);
var g=Math.floor(imgData.data[i+1]/4);
var b=Math.floor(imgData.data[i+2]/4);
var a=255;
var lutX = (b % 8) * 64 + r;
var lutY = Math.floor(b / 8) * 64 + g;
var lutIndex = (lutY * lutWidth + lutX)*4;
var Rr = filterData.data[lutIndex];
var Gg = filterData.data[lutIndex+1];
var Bb = filterData.data[lutIndex+2];
imgData.data[i] = Rr;
imgData.data[i+1] = Gg;
imgData.data[i+2] = Bb;
imgData.data[i+3] = 255;
}
Compruébelo aquí: http://jsfiddle.net/gxu080ve/1/ La imagen oculta está en código de bytes, lo siento por eso.
Este código solo se aplica a las imágenes 3DLUT de 64x64x64. Los parámetros varían si su LUT tiene otras dimensiones; el / 4
, * 64
, % 8
, / 8
debe cambiarse para otras dimensiones, pero en el alcance de esta pregunta el LUT es 64x64x64.