如何在 JavaScript 中使用 LUT? [英] How to use LUT with JavaScript?

查看:49
本文介绍了如何在 JavaScript 中使用 LUT?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是图像处理的新手.

我想使用 JavaScript 将效果应用于使用 LUT(查找表)或相应查找 PNG 的图像,如下所示:

我在谷歌上搜索了很多,但找不到一篇文章或任何资源来描述使用 LUT 进行像素转换的确切过程.

我在 lut 图像是字节码,对不起.

此代码仅适用于 64x64x64 3DLUT 图像.如果您的 LUT 具有其他维度,则参数会有所不同;/4, * 64, % 8, /8 必须改成其他维度,但是在这个问题的范围 LUT 是 64x64x64.

I'm new to image processing.

I want to use JavaScript to apply effects to images using LUTs (LookUp Tables) or the corresponding lookup PNGs, something like this:

I have googled a lot and couldn't find an article or any resource which will describe the exact process of pixel transformation using LUTs.

I have found a nice article here, which describes the 1D and 3D LUTs and the differences between them. But its still is not fully clear for me.

I want something like this, which is done for iOS.

P.S. Please do not post links/answers regarding image filtering libs, which are using convolution matrices for effects or for filters.

Update:

Finally! I have got the answer thanks to @abbath. I've created a gist in GitHub, which you can find here.

解决方案

I am also new to the topic, but I hope it helps what I've found out so far. Your image (the LUT) is a representation of a 3D array, imagine a 64x64x64 cube. This representation is in 2D, one plane is a 64x64 square. You need 64 piece of this plane, which is why the png has 8x8 squares in it. If you look carefully, the upperleft square has red (R of RGB) on the X axis and green (G) on the Y axis. The blue (B) is the Z axis (I imagine it upwards), which can't be representated in 2D, so it comes on the next 64x64 squares. On the last (lower right) square you can see that it is mostly blue, where the red and green coordinates are 0.

So the next question is how to project an image with this LUT. I have tried it out in Java, in my opinion you will have to lose some information because 64x64x64 is far less than 256x256x256, in this case, you have to divide by 4 each pixel color value.

The steps:

  1. Iterate through the pixels of your original image. In one iteration you will have one pixel of the original image. Get the R, G, B values of that pixel.
  2. Divide the values by four, so you will have a value less than 64.
  3. Get the corresponding pixel from your LUT, as if it was a 64x64x64 cube. So if RGB=(255,0,255) was on the original pixel, than divide it to get (63,0,63), then check the B value, to get the corresponding square on the png, which will be the lower right one (in the case of b=63), and get the r,g=(63,0) pixel of it, which purpleish on your png image.

I checked now on android, with java code, its fast enough in my opinion. Below is the code I've written, I hope it's enough to port it to javascript. (I hope the comments are enough to understand)

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 ;
}

Now I've successfully implemented in javascript too, check for using the Math.floor() functions:

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;

}

Check it here: http://jsfiddle.net/gxu080ve/1/ The lut image is in byte code, sorry for that.

This code only applies for 64x64x64 3DLUT images. The parameters vary if your LUT has other dimensions; the / 4, * 64, % 8, / 8 must be changed for other dimensions, but in this question's scope the LUT is 64x64x64.

这篇关于如何在 JavaScript 中使用 LUT?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆