简体   繁体   English

如何在IOS中将LUT(颜色查找表)应用于CGImage或UIImage?

[英]How do I apply a LUT (Color Look-Up Table) to a CGImage or UIImage in IOS?

Given a CGImage or UIImage, how can I apply a custom color look-up table (aka LUT, CLUT, Color Map)? 给定CGImage或UIImage,如何应用自定义颜色查找表(也称为LUT,CLUT,Color Map)? That is, how can I map the colors in the image to new colors, given a mapping? 也就是说,在给定映射的情况下,如何将图像中的颜色映射到新颜色?

I will describe three approaches that you can take. 我将描述您可以采取的三种方法。

  1. Do it manually 手动完成
  2. Use a CIFilter (available in iOS 5) 使用CIFilter (iOS 5中提供)
  3. Use a shader (GPU program) 使用着色器(GPU程序)

Manual Approach 手动方法

First, get the raw image data from the UIImage. 首先,从UIImage获取原始图像数据。 You may do this by creating a byte array of the appropriate size (width * height * components), then drawing into it with CGBitmapContext. 您可以通过创建适当大小的字节数组(width * height * components),然后使用CGBitmapContext绘制它来完成此操作。 Something like this: 像这样的东西:

    using (var colorSpace = CGColorSpace.CreateDeviceRGB())
    using (var context = new CGBitmapContext(
        bytes, width, height, bitsPerComponent, bytesPerRow, 
        colorSpace, CGBitmapFlags.ByteOrder32Big | CGBitmapFlags.PremultipliedLast))
    {
        var drawRect = new RectangleF(-rectangle.X, -rectangle.Y, image.CGImage.Width, image.CGImage.Height);
        context.ClipToRect(new RectangleF(0, 0, width, height));
        context.DrawImage(drawRect, image.CGImage);
    }

Then create an array of bytes for your output image (probably the same size). 然后为输出图像创建一个字节数组(可能大小相同)。 Iterate over the input image looking up color values in your Look-Up Table and writing them to the output image. 迭代输入图像,查找查找表中的颜色值并将其写入输出图像。

You may convert the output bytes to an image by constructing a CGDataProvider from the bytes, then a CGImage from that, and then a UIImage from the CGImage . 您可以通过从字节构造CGDataProvider ,然后CGImage ,然后从CGImage UIImage ,将输出字节转换为图像。

CIFilter Approach CIFilter方法

As of iOS 5, Apple provides many built-in image operations. 从iOS 5开始,Apple提供了许多内置的图像操作。 Generally, these are easy to use and faster than doing it manually. 通常,这些都比手动操作更容易使用和更快。 However, depending on how your color look-up table is specified, you might not find a perfect fit. 但是,根据您的颜色查找表的指定方式,您可能找不到完美的搭配。

Given a CIFilter, you may set the inputImage, then retrieve the output from the OutputImage property. 给定一个CIFilter,您可以设置inputImage,然后从OutputImage属性中检索输出。 See the documentation for a list of filters in the CICategoryColorAdjustment and CICategoryColorEffect categories. 有关CICategoryColorAdjustment和CICategoryColorEffect类别中的过滤器列表,请参阅文档 As of this writing, I would suggest looking at CIToneCurve, CIFalseColor, CIColorMap and CIColorCube. 在撰写本文时,我建议您查看CIToneCurve,CIFalseColor,CIColorMap和CIColorCube。 Sadly, at the time of writing, CIColorMap is not available on iOS. 可悲的是,在撰写本文时,CIColorMap在iOS上不可用。

If you are doing scientific imaging, and you only use a linear gradient between two colors, I suggest looking at CIFalseColor . 如果您正在进行科学成像,并且您只使用两种颜色之间的线性渐变,我建议您查看CIFalseColor

Here is an example of populating a CIColorCube with a random color look-up function. 以下是使用随机颜色查找功能填充CIColorCube的示例。 Note that CIFilters may be created dynamically by name (not type-safe) or in a strongly-typed way. 请注意,可以按名称(非类型安全)或强类型方式动态创建CIFilter。 If you know what filter you want to use at code-time, I suggest using the strongly-typed filter ( CIColorCube rather than CIFilter.FromName("CIColorCube") ). 如果你知道在代码时想要使用什么过滤器,我建议使用强类型过滤器( CIColorCube而不是CIFilter.FromName("CIColorCube") )。 I am using the dynamic approach in the following example, as it is more confusing. 我在下面的例子中使用动态方法,因为它更令人困惑。

static void PopulateColorCubeFilter(CIFilter filter)
{
    if (filter.Name != "CIColorCube")
        return;

    int dimension = 64;  // Must be power of 2, max of 128 (max of 64 on ios)
    int cubeDataSize = 4 * dimension * dimension * dimension;
    filter[new NSString("inputCubeDimension")] = new NSNumber(dimension);

    // 2 : 32 /4 = 8 = 2^3
    // 4 : 256 /4 = 64 = 4^3
    // 8 : 2048 /4 = 512 = 8^3

    var cubeData = new byte[cubeDataSize];
    var rnd = new Random();
    rnd.NextBytes(cubeData);
    for (int i = 3; i < cubeDataSize; i += 4)
        cubeData[i] = 255;
    filter[new NSString("inputCubeData")] = NSData.FromArray(cubeData);
}

GPU Shader Approach GPU着色器方法

Finally, the most general-purpose high-performance approach that remains correct under magnification would be to do the color mapping on the GPU. 最后,在放大率下保持正确的最通用的高性能方法是在GPU上进行颜色映射。 This is more effort than the first two approaches, so you need to decide if it is worth it. 这比前两种方法更省力,所以你需要决定它是否值得。

  1. Load one texture map (aka Sampler2D) with your input image 使用输入图像加载一个纹理贴图(也称为Sampler2D)
  2. Load a second texture map with your color map (practically it is a 1D Texture, but with OpenGL ES probably needs to be loaded as a 2D Texture) 使用颜色贴图加载第二个纹理贴图(实际上它是一维纹理,但OpenGL ES可能需要作为2D纹理加载)
  3. Apply the two texture maps and a shader to a quad 将两个纹理贴图和着色器应用于四边形
  4. In the shader use the texture coordinates to look up the color in the first texture, then use the value in the first texture to look up in the second texture. 在着色器中使用纹理坐标查找第一个纹理中的颜色,然后使用第一个纹理中的值在第二个纹理中查找。 That is your output color. 那是你的输出颜色。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM