Getting started with core image

Time:2022-5-7

Original link:http://1199game.com/2016/06/B…
Core image is a powerful image processing framework. Using core image can easily implement filters, such as modifying image deformation, color and exposure. It uses GPU (or CPU) to process image data, so it is very fast and can process every frame of video in real time.

Multiple filters of core image can be combined to process video frames or images at the same time. When multiple filters are used together, it is more efficient, because when combined, only one synthetic filter needs to be created to process the image. If separated, each filter needs to be created.

Each filter has its own parameters, which can be obtained in the code. You can also query various filters that the system can provide. There are fewer filters available on IOS than on MAC, which is a subset of MAC.

In this article, I will teach you how to use core image. I will teach you how to use various filters, and you will find that it is very simple to achieve a cool effect on the picture.

Core image overview

Before we start, let’s briefly introduce several important classes in the core image framework.

·Cicontext: all processing of core image is completed by cicontext, which is somewhat similar to the context of core graphics and OpenGL.

·Ciimage: this class holds image data, which can be created with uiimage, image file or pixel data.

·Ciflite: this class represents a filter. It has many properties and is internally maintained by a dictionary. There are many kinds of filters, such as image deformation filters, filters that can change the color of images, filters that can cut images, and so on

These classes will be used in your project next.

start

Open Xcode, create a new single view application project named coreimagefun, and select device as iPhone.

The first thing to create a good project is to add the core image framework to the project. On the Mac platform, the coreimage framework is a part of the quartzcore framework. On the IOS platform, it is an independent framework. How to add a framework to the project will not be discussed in detail here. No, please check the relevant documents.

Next, download the files that will be used in the projectresources, resources will be added to your project.

Next, create a uiimageview in viewload. The code is as follows

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.view.backgroundColor = [UIColor whiteColor];
    
    _imageView = [[UIImageView alloc] init];
    [self.view addSubview:_imageView];
    _imageView.bounds = CGRectMake(0, 0, self.view.width, 300);
    _imageView.centerX = self.view.width / 2.0f;
    _imageView.top = 0;
    //.......
}

Note: positioning used in the project

Basic filter effect

Next, implement a very simple filter effect and display it on ImageView.

Each time the effect of the filter is realized, it basically includes the following four steps:

1. Create ciimage object: ciimage has many initialization methods, such as imagewithurl:, imagewithdata:, imagewithcvpixelbuffer:, and imagewithbitmapdata: bytesperrow: size: Format: colorspace:, in most cases, imagewithurl: is enough.
2. Create cicontext object: a cicontext object can use CPU or GPU. Cicontext can be reused, so there is no need to create cicontext objects repeatedly.
3. Create cifilter object: when creating a cifilter object, you can set a series of properties according to the filter effect you need to achieve.
4. Get the output object of the filter: cifilter will output a picture that meets your expected effect according to the properties you set. This picture is an object of type ciimage, which can be converted into uiimage with cicontext

See how the code is implemented. In viewcontroller Add the following code to the viewdidload: method of the m file:

// 1
NSString *filePath =
  [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"];
NSURL *fileNameAndPath = [NSURL fileURLWithPath:filePath];
 
// 2
CIImage *beginImage =
  [CIImage imageWithContentsOfURL:fileNameAndPath];
 
// 3
CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"
                              keysAndValues: kCIInputImageKey, beginImage,
                    @"inputIntensity", @0.8, nil];
CIImage *outputImage = [filter outputImage];
 
// 4
UIImage *newImage = [UIImage imageWithCIImage:outputImage];
self.imageView.image = newImage;

The above code means:

1. The first two lines of code create an nsurl object to represent the path of the image.

2. Next, create a ciimage object with the imagewithcontentsofurl method.

3. Create a cifilter object. The construction method of this object passes two parameters. The first parameter is the name of the filter, and the second parameter is a dictionary, which represents some parameters of the filter.

Cisepiatone only needs two parameters, kciinputimagekey and @ “inputintensity”. Kciinputimagekey represents an image. Inputintensity is a value of float type, wrapped in nsnumber. Its range is 0-1. Here, it is set to 0.8. Most filters have default values, which are used if they are not set manually. It has no default except ciimage. It’s easy to get the image after using the filter. Just get the outputimage property.

4. Once you get the output ciimage, you can convert it into a uiimage. In ios6, you can use uiimage method + imagewithciimage: to complete this step. This method uses a ciimage object to create a uiimage. Once you create a uiimage object, you can display it on the image view.

After compiling and running, you will see a picture processed by the filter. Congratulations, now you have learned to use ciimage and cifilter!!!!, The effect is as follows:

Getting started with core image

Use context

Before continuing the tutorial, you need to know a small optimization.

As mentioned earlier, cicontext is used to handle ciflite, but cicontext is not used in the above example. This is because the above example directly uses the imagewithciimage method of uiimage. All work has been done inside imagewithciimage. It creates a cicontext object inside, and then uses this object to obtain the output image.

There is a disadvantage in this way – a cicontext object will be created every time. In fact, the cicontext object can be reused. If you use a slide control to update the value of filter, if you use the above code, you will create a cicontext object every time, which is very inefficient.

Next, improve the above code, delete the above code and replace it with the following code.

CIImage *beginImage =
  [CIImage imageWithContentsOfURL:fileNameAndPath];
 
// 1
CIContext *context = [CIContext contextWithOptions:nil];
 
CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"
                              keysAndValues: kCIInputImageKey, beginImage,
                    @"inputIntensity", @0.8, nil];
CIImage *outputImage = [filter outputImage];
 
// 2
CGImageRef cgimg =
  [context createCGImage:outputImage fromRect:[outputImage extent]];
 
// 3
UIImage *newImage = [UIImage imageWithCGImage:cgimg];
self.imageView.image = newImage;
 
// 4
CGImageRelease(cgimg);

The above code is explained below:

1. A cicontext object is created here. Its construction method passes a dictionary, which can execute color and whether to use CPU or GPU. Here, we can use the default attribute, so just pass a nil.

2. Use the context object to create a cgimage and call createcgimage: fromrect: to create a cgimageref.

3. Next, use uiimage + imagewithcgimage to convert the cgimage created in the previous step into uiimage.

4. Finally, release cgimageref. Cgimage is a C API and requires manual memory management, even in arc mode.

Compile and run to ensure that the result is the same as before.

In this example, creating a cicontext object alone is not very different from the previous method, but in the next example, you will find that it will be very different.

Change the value of filter

Next, we add a slide control to change the value of filter in real time.

The interface is as follows:
Getting started with core image
The created code is as follows:

1. Create slider control
_amountSlider = [[UISlider alloc] init];
    [self.view addSubview:_amountSlider];
    _amountSlider.bounds = CGRectMake(0, 0, self.view.width - 40, 44);
    _amountSlider.top = _imageView.bottom + 20.0f;
    _amountSlider.centerX = self.view.width / 2.0f;
    [_amountSlider addTarget:self action:@selector(amountSliderValueChanged:) forControlEvents:UIControlEventValueChanged];
2. Callback method
- (void)amountSliderValueChanged:(UISlider *)slider {
    NSLog(@"amountSliderValueChanged...");
    float slideValue = slider.value;
    [filter setValue:@(slideValue) forKey:@"inputIntensity"];
    CIImage *outputImage = [filter outputImage];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    UIImage *newImage = [UIImage imageWithCGImage:cgimg];
    _imageView.image = newImage;
    CGImageRelease(cgimg);
}

Every time you change the slider value, you need to filter the image again. However, you don’t need to do everything every time, which will be inefficient. You only need to change a little bit, so some need to be changed to global variables.

The most important thing is to reuse cicontext objects. If you create them every time, the efficiency is too low. In addition, cifilter and initial ciimage objects are put into global variables, which can be reused.

Therefore, these three variables need to be regarded as member variables of viewcontroller. The code is as follows:

@implementation ViewController {
    CIContext *context;
    CIFilter *filter;
    CIImage *beginImage;
}

The initialization method in viewload should also be changed accordingly.

beginImage = [CIImage imageWithContentsOfURL:fileNameAndPath];
context = [CIContext contextWithOptions:nil];
 
filter = [CIFilter filterWithName:@"CISepiaTone" 
  keysAndValues:kCIInputImageKey, beginImage, @"inputIntensity", 
  @0.8, nil];

Now we need to implement the method of changevalue. In this method, we need to change the value corresponding to @ “inputintensity” in the dictionary of cifilter. Once this value is changed, we need to perform the following three steps:

1. Get the output image of cifilter.

2. Convert ciimage to cgimageref.

3. Convert cgimageref to uiimage and display it on image view.

So the code in amountslidervaluechanged is as follows:

- (void)amountSliderValueChanged:(UISlider *)slider {
    NSLog(@"amountSliderValueChanged...");
    float slideValue = slider.value;
    [filter setValue:@(slideValue) forKey:@"inputIntensity"];
    CIImage *outputImage = [filter outputImage];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    UIImage *newImage = [UIImage imageWithCGImage:cgimg];
    _imageView.image = newImage;
    CGImageRelease(cgimg);
}

This code obtains the float value from the slider. The value of the slide ranges from 0-1, which is just the same as the value range in cifilter. This is very convenient and can be used directly.

After compiling and running, you move the slide, and you will find different effects. The effects are as follows:

Getting started with core image

Get photos from album

Now you can dynamically change the value of the filter, which seems very interesting. But just filtering this fixed image is boring. Next, use UIImagePickerController to get the pictures of the album and wake up the filter.

Create a button to open the album. The interface is as follows:
Getting started with core image
The click method of this button is loadphoto, and the code is as follows:

- (IBAction)loadPhoto:(id)sender {
    UIImagePickerController *pickerC = 
      [[UIImagePickerController alloc] init];
    pickerC.delegate = self;
    [self presentViewController:pickerC animated:YES completion:nil];
}

The first line instantiates a UIImagePickerController and sets self as its delegate.

There will be a warning here. You need to implement uiimagepickercontrollerdelegate and uinaviationcontrollerdelegate protocols. The code is as follows:

@interface ViewController () <UIImagePickerControllerDelegate, UINavigationBarDelegate>
@end

- (void)imagePickerController:(UIImagePickerController *)picker 
  didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [self dismissViewControllerAnimated:YES completion:nil];
    NSLog(@"%@", info);
}
 
- (void)imagePickerControllerDidCancel:
  (UIImagePickerController *)picker {
    [self dismissViewControllerAnimated:YES completion:nil];
}

In both methods, it is dimiss uipickercontroller.

The first method has not been fully implemented. Here is the complete implementation:

- (void)imagePickerController:(UIImagePickerController *)picker
  didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [self dismissViewControllerAnimated:YES completion:nil];
    UIImage *gotImage =
      [info objectForKey:UIImagePickerControllerOriginalImage];
    beginImage = [CIImage imageWithCGImage:gotImage.CGImage];
    [filter setValue:beginImage forKey:kCIInputImageKey];
    [self amountSliderValueChanged:self.amountSlider];
}

The complete example is inhere

reference:http://www.raywenderlich.com/22167/beginning-core-image-in-ios-6