Given a CGImage or UIImage, how can I apply a custom color look-up table (aka 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.
First, get the raw image data from the UIImage. You may do this by creating a byte array of the appropriate size (width * height * components), then drawing into it with 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
.
As of iOS 5, Apple provides many built-in image operations. 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. See the documentation for a list of filters in the CICategoryColorAdjustment and CICategoryColorEffect categories. As of this writing, I would suggest looking at CIToneCurve, CIFalseColor, CIColorMap and CIColorCube. Sadly, at the time of writing, CIColorMap is not available on iOS.
If you are doing scientific imaging, and you only use a linear gradient between two colors, I suggest looking at CIFalseColor .
Here is an example of populating a CIColorCube with a random color look-up function. Note that CIFilters may be created dynamically by name (not type-safe) or in a strongly-typed way. 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")
). 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);
}
Finally, the most general-purpose high-performance approach that remains correct under magnification would be to do the color mapping on the GPU. This is more effort than the first two approaches, so you need to decide if it is worth it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.