如何在JavaScript中使用LUT?

如何在JavaScript中使用LUT?,javascript,image-processing,lookup-tables,Javascript,Image Processing,Lookup Tables,我是图像处理新手 我想使用JavaScript使用LUT(查找表)或相应的查找PNG将效果应用于图像,如下所示: 我在谷歌上搜索了很多,没有找到一篇文章或任何资源来描述使用LUT进行像素转换的确切过程 我发现了一篇很好的文章,它描述了1D和3D LUT以及它们之间的差异。但我还是不太清楚 我想要像这样的东西,这是为iOS做的 另外,请不要发布有关图像过滤LIB的链接/答案,这些LIB使用卷积矩阵进行效果或过滤器 更新: 终于!多亏了@abbath,我才得到了答案。我在GitHub中创建了一个要

我是图像处理新手

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

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

我发现了一篇很好的文章,它描述了1D和3D LUT以及它们之间的差异。但我还是不太清楚

我想要像这样的东西,这是为iOS做的

另外,请不要发布有关图像过滤LIB的链接/答案,这些LIB使用卷积矩阵进行效果或过滤器

更新:


终于!多亏了@abbath,我才得到了答案。我在GitHub中创建了一个要点,您可以找到。

我对这个主题也不熟悉,但我希望它能帮助我目前所发现的内容。您的图像(LUT)是一个3D阵列的表示,请想象一个64x64x64立方体。此表示是二维的,一个平面是64x64正方形。你需要64块这个平面,这就是为什么png中有8x8个正方形。 如果仔细观察,左上角的正方形在X轴上有红色(R表示RGB),在Y轴上有绿色(G)。蓝色(B)是Z轴(我想象它向上),它不能在2D中表示,所以它出现在接下来的64x64正方形上。在最后一个(右下角)正方形上,您可以看到它大部分是蓝色的,其中红色和绿色坐标为0

所以下一个问题是如何用这个LUT投影图像。我已经在Java中试用过,我认为您将不得不丢失一些信息,因为64x64x64远小于256x256x256,在这种情况下,每个像素颜色值必须除以4

步骤如下:

  • 遍历原始图像的像素。在一次迭代中,您将拥有原始图像的一个像素。获取该像素的R、G、B值
  • 将这些值除以四,使值小于64
  • 从LUT中获取相应的像素,就像它是一个64x64x64立方体一样。因此,如果RGB=(255,0255)位于原始像素上,则将其除以得到(63,0,63),然后检查B值,以获得png上的相应正方形,即右下角的正方形(在B=63的情况下),并获得其r,g=(63,0)像素,这将在png图像上显示
  • 我现在检查了android,使用java代码,我认为它足够快了。下面是我编写的代码,我希望它足以将其移植到javascript。(我希望这些评论足以让人理解)

    public位图applyEffectToBitmap(位图src、位图lutbramp){
    //android特定代码,将LUT图像的像素存储在int数组中
    int lutWidth=lutBitmap.getWidth();
    int-lutColors[]=new-int[lutWidth*lutBitmap.getHeight();
    getPixels(lutColor,0,lutWidth,0,0,lutWidth,lutBitmap.getHeight());
    //android特定代码,将源图像的像素存储在int数组中
    int srcWidth=src.getWidth();
    int srchheight=src.getHeight();
    int[]pix=新int[srcWidth*srcHeight];
    getPixels(像素,0,srcWidth,0,0,srcWidth,srcHeight);
    int R,G,B;
    //现在我们可以遍历源图像的像素
    对于(int y=0;y>16)和0xff)/4;
    intg=((pix[index]>>8)和0xff)/4;
    intb=(pix[索引]&0xff)/4;
    //神奇之处就在这里:上面的第三步:蓝色像素描述了
    //您需要从哪个正方形的列和行获取像素
    //然后简单地加上r和green值得到坐标
    int lutX=(b%8)*64+r;
    int-lutY=(b/8)*64+g;
    int-lutIndex=lutY*lutWidth+lutX;
    //与上面得到的像素相同,但现在来自LutColor int数组
    R=((lutColors[lutIndex]>>16)和0xff);
    G=((lutColors[lutIndex]>>8)和0xff);
    B=((lutColors[lutIndex])&0xff);
    //用过滤后的值覆盖pix数组,在我的例子中alpha是256,但您可以使用原始alpha
    
    pix[索引]=0xff000000|(r> p>我尝试在C++中做类似的事情。3D LUT通常有3列值,通常在0到1之间。列分别是R G B,它们代表值的映射。如果打开这些大小为nxnxn的文件中的一个,则将每个值读入相应的R数组或G数组或B数组。然后在内部重新创建映射,您将迭代并使用双/浮点键和值填充rgb贴图

    for every b
        for every g
            for every r
                // r g and b are indices
                index = b * n^2 + g * n + r
                Rmap.push((r + 1)/n, Rarray[index])
                // Same for g and b
                Gmap.push((g + 1)/n, Garray[index]
                Bmap.push((b + 1)/n, Barray[index]
    

    一旦有了映射,就可以对图像中的每个像素应用查找。假设图像的最大颜色为255,则取(r,g,b)/每个像素的255,然后应用查找,然后转换回*255。据我所知,计算无法查找的值的惯例是执行三线性插值。我还没有太多成功,但这是我的两美分。

    谢谢你的回答。我有一些问题:你说的
    获取相应的值是什么意思LUT中的像素
    ?如果我的图像大于LUT怎么办?如何
    检查B值
    ?以及在执行步骤后,如何使用结果
    更改图像的当前像素(63,0)
    ?您的图像可以有任何大小,您必须遍历图像的每一个像素。因此,如果您有全高清图像,您必须遍历1080*1920像素。在一次迭代中,您将有一个像素值。获取该像素的r、g和b值。它们将小于256,但需要小于64,因此将所有三个值除以4.现在一个像素有三个值,每个值在64以下。然后是y
    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;
    
    }
    
    for every b
        for every g
            for every r
                // r g and b are indices
                index = b * n^2 + g * n + r
                Rmap.push((r + 1)/n, Rarray[index])
                // Same for g and b
                Gmap.push((g + 1)/n, Garray[index]
                Bmap.push((b + 1)/n, Barray[index]