Class

CIImageProcessorKernel

The abstract class you extend to create custom image processors that can integrate with Core Image workflows.

Declaration

@interface CIImageProcessorKernel : NSObject

Overview

Unlike the CIKernel class and its other subclasses that allow you to create new image-processing effects with the Core Image Kernel Language, the CIImageProcessorKernel class provides direct access to the underlying bitmap image data for a step in the Core Image processing pipeline. As such, you can create subclasses of this class to integrate other image-processing technologies—such as Metal compute shaders, Metal Performance Shaders, Accelerate vImage operations, or your own CPU-based image-processing routines—with a Core Image filter chain.

Your custom image processing operation is invoked by your subclassed image processor kernel's processWithInputs:arguments:output:error: method. The method can accept zero, one or more inputs: kernels that generate imagery (such as a noise or pattern generator) need no inputs, while kernels that composite source images together require multiple inputs. The arguments dictionary allows the caller to pass in additional parameter values (such as the radius of a blur) and the output contains the destination for your image processing code to write to.

The following code shows how you can subclass CIImageProcessorKernel to apply the Metal Performance Shader MPSImageThresholdBinary kernel to a CIImage:

Listing 1

Creating a Threshold Image Processing Kernel

class ThresholdImageProcessorKernel: CIImageProcessorKernel {
static let device = MTLCreateSystemDefaultDevice()        
override class func process(with inputs: [CIImageProcessorInput]?, arguments: [String : Any]?, output: CIImageProcessorOutput) throws {                
    guard            
        let device = device,            
        let commandBuffer = output.metalCommandBuffer,            
        let input = inputs?.first,            
        let sourceTexture = input.metalTexture,            
        let destinationTexture = output.metalTexture,            
        let thresholdValue = arguments?["thresholdValue"] as? Float else  {                
            return        
        }                
    
    let threshold = MPSImageThresholdBinary(
        device: device,                                                
        thresholdValue: thresholdValue,                                               
        maximumValue: 1.0,                                                
        linearGrayColorTransform: nil)                
    
    threshold.encode(
        commandBuffer: commandBuffer,                         
        sourceTexture: sourceTexture,                         
        destinationTexture: destinationTexture)    
    }
}

To apply to kernel to an image, the calling side invokes the image processor's applyWithExtent:inputs:arguments:error: method. The following code generates a new CIImage object named result which contains a thresholded version of the source image, inputImage.

let result = try? ThesholdImageProcessorKernel.apply( 
    withExtent: inputImage.extent,            
    inputs: [inputImage],            
    arguments: ["thresholdValue": 0.25])

Subclassing Notes

The CIImageProcessorKernel class is abstract; to create a custom image processor, you define a subclass of this class.

You do not directly create instances of a custom CIImageProcessorKernel subclass. Image processors must not carry or use state specific to any single invocation of the processor, so all methods (and accessors for readonly properties) of an image processor kernel class are class methods.

Your subclass should override at least the processWithInputs:arguments:output:error: method to perform its image processing.

If your image processor needs to work with a larger or smaller region of interest in the input image than each corresponding region of the output image (for example, a blur filter, which samples several input pixels for each output pixel), you should also override the roiForInput:arguments:outputRect: method.

You can also override the formatForInputAtIndex: method and outputFormat property getter to customize the input and output pixel formats for your processor (for example, as part of a multi-step workflow where you extract a single channel from an RGBA image, apply an effect to that channel only, then recombine the channels).

Using a Custom Image Processor

To apply your custom image processor class to filter one or more images, call the applyWithExtent:inputs:arguments:error: class method. (Do not override this method.)

Topics

Type Properties

outputFormat

The processor's output pixel format.

outputIsOpaque

Boolean determining whether or not processor outputs an opaque image.

synchronizeInputs

Tells whether or not processor input should be synchronized for CPU access.

Type Methods

+ applyWithExtent:inputs:arguments:error:

Method to override when applying a custom image processor kernel to an image and returning the result.

+ formatForInputAtIndex:

Method to override for returning the image processing kernel's input pixel format.

+ processWithInputs:arguments:output:error:

Method to override for customizing the kernel's image processing.

+ roiForInput:arguments:outputRect:

Method to override for determining specific region of input image required to process in rendering a specified region of the output image.

Relationships

Inherits From

See Also

Custom Image Processors

CIImageProcessorInput

A container of image data and information for use in a custom image processor.

CIImageProcessorOutput

A container for writing image data and information produced by a custom image processor.