How to use CIColorMatrix in iOS5?
Asked Answered
S

2

7

I'm trying to find out how to change the color/hue of a UIImage. I found out that iOS5 has a lot of image filters, but I have hard time finding documentation on the proper use of the CIColorMatrix filter.

-(void)doCIColorMatrixFilter
{

    //does not work, returns nil image
    CIImage* inputImage = [CIImage imageWithCGImage:[[UIImage imageNamed:@"button.jpg"]CGImage]];

    CIFilter *myFilter;
    NSDictionary *myFilterAttributes;
    myFilter = [CIFilter filterWithName:@"CIColorMatrix"];
    [myFilter setDefaults];

    myFilterAttributes = [myFilter attributes];

    [myFilterAttributes setValue:inputImage forKey:@"inputImage"];
    //How to set up attributes?

    CIContext *context = [CIContext contextWithOptions:nil];
    CIImage *ciimage = [myFilter outputImage];
    CGImageRef cgimg = [context createCGImage:ciimage fromRect:[ciimage extent]];
    UIImage *uimage = [UIImage imageWithCGImage:cgimg scale:1.0f orientation:UIImageOrientationUp];
    [imageView setImage:uimage];
    CGImageRelease(cgimg);

}

What code goes into the dictionary for this filter?

Squarerigger answered 27/2, 2012 at 21:41 Comment(0)
C
23

One month later ...

This is an example of CIColorMatrix setting all its parameters :)

-(void)doCIColorMatrixFilter
{
    // Make the input image recipe
    CIImage *inputImage = [CIImage imageWithCGImage:[UIImage imageNamed:@"facedetectionpic.jpg"].CGImage]; // 1

    // Make the filter
    CIFilter *colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; // 2
    [colorMatrixFilter setDefaults]; // 3
    [colorMatrixFilter setValue:inputImage forKey:kCIInputImageKey]; // 4
    [colorMatrixFilter setValue:[CIVector vectorWithX:1 Y:1 Z:1 W:0] forKey:@"inputRVector"]; // 5
    [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:1 Z:0 W:0] forKey:@"inputGVector"]; // 6
    [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:1 W:0] forKey:@"inputBVector"]; // 7
    [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"]; // 8

    // Get the output image recipe
    CIImage *outputImage = [colorMatrixFilter outputImage];  // 9

    // Create the context and instruct CoreImage to draw the output image recipe into a CGImage
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]]; // 10

    // Draw the image in screen
    UIImageView *imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:cgimg]];
    CGRect f = imageView2.frame;
    f.origin.y = CGRectGetMaxY(imageView.frame);
    imageView2.frame = f;

    [self.view addSubview:imageView2];
}

So this is what the sample does:

In 1 we create the ciimage, if you are getting nil there then make sure you are passing the right UIImage/CGImage or path.

In 2 create the filter, you know this :)

In 3 set the filter parameters to its defaults, CoreImage Programming guide suggests we should do this although (I haven't experimented any strange/bad things if avoided.)

In 4 set the input ciimage

From 5 through 8 we set the parameters. For example I made the red vector {1,1,1,0} so the image looks reddish. 6, 7 and 8 and not necessary here since their values are the same as the defaults (remember we called -setDefaults?) but for educational purposes I guess they are fine :)

In 9 set the output image, although is not drawn yet.

Finally in 10 you tell CoreImage to draw the output image into a CGImage, and we put that CGImage into an UIImage and it inside an UIImageView.

This is the result (I used the same image as this tutorial):

Reddish

Hope it helps.

Cent answered 24/3, 2012 at 18:55 Comment(3)
Great great answer. Just a side note with the #1 note. Sometimes the ciimage is nil because of the image type. So sometimes its necessary to create cgimage and then a ciimage from that.Heparin
@Heparin Could you give an example of an image type that will return nil for ciimage? I would like to edit the answer addressing it :)Cent
Heres an article that explains the 3. medium.com/@ranleung/uiimage-vs-ciimage-vs-cgimage-3db9d8b83d94 . If you are working with a known type (say a .jpg) and you always know you'll have the CIImage then you're safe. But if your app takes multiple types of file formats then you should have safeguards for when CIImage is nil and instead grab the CGImage and convert that to CIImage (which can mean re-drawing it in the context and grabbing the UIImage->CIImage from that)Heparin
H
6

Just a Swift example with a chain to add to above answer by nacho4d

var output = CIFilter(name: "CIColorControls")
output.setValue(ciImage, forKey: kCIInputImageKey)
output.setValue(1.8, forKey: "inputSaturation")
output.setValue(0.01, forKey: "inputBrightness")

filter = CIFilter(name: "CIColorMatrix")
filter.setDefaults()
filter.setValue(output.outputImage, forKey: kCIInputImageKey)
filter.setValue(CIVector(x: 1, y: 0.1, z: 0.1, w: 0), forKey: "inputRVector")
filter.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: "inputGVector")
filter.setValue(CIVector(x: 0, y: 0, z: 1, w: 0), forKey: "inputBVector")

Note that the defaults are 1,0,0 0,1,0 and 0,0,1 respectively for RGB and if you want to make it more red you would set the inputRVector to 1,1,1 and leave the others the same (as this multiples the blue and green components by red values)

Heparin answered 23/12, 2014 at 19:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.