Using Metal Shading Language for Custom CIKernels — Metal & Swift

Mert Tuzer
3 min readApr 24, 2020

--

While there are plenty of built-in Core Image filters (CIFilter) provided by Apple, one may want to touch each pixel of still images or video images on his/her own. That’s why we have Metal Shading Language to implement our custom CIKernels and subsequently CIFilters of our own.

As Apple states, CIKernels are image processing routines for CIFilters. While CIFilter determines the input images and/or parameters of the processing procedure, CIKernel of that filter does the job and produces a processed image by benefiting those images and parameters.

First of all, the custom CIFilter is created by defining needed variables-constants, and the custom kernel to be implemented in a metal file. Below, we have an example of such a custom class that will paint the image with different colors in three divisions.

Let’s overview the important steps one by one.

(1) We set our raw image to be processed. We could also define various parameters in this section depending on our processing inquiries.

(2) The kernel must be implemented in a metal file and addressed here so that we can employ.

(3) Special to our custom class, we define three vectors in the CIVector format to control the colors of the three divisions. (However, if we want, we could define these vectors as parameters of our filter.)

(4) This statement is for pointing region of interest we need to process in our image. Here we process on the whole image.

(5) Lastly, we give our arguments to the kernel to get back the new processed image.

Now, we are ready to implement our kernel in a new metal file so that it can be accessed as needed in step 2.

For our custom metal file, the important steps are as follows:

(1) CoreImage must be included so that we can use the features of CI.

(2) Not mandatory but, we can define functions to use in our kernel functions.

(3) To be able to call from CIFilters, we need to employ this statement and define our kernel function with arguments given same as with the ones in the custom CIFilter class.

(4) The pixel to be processed is found by calling the position and sampling the image matrix at that position. (The coordinates are always scaled in the range 0–1. Not in this post, but we may have a special argument “destination” that spans real coordinates of the image.)

(5) Depending on the vertical coordinate y, we multiply colors so that the image at the end has three different regions separated by colors.

A simple usage of this custom filter might be achieved by typing this block:

let filter = ThreeDyeFilter()
filter.inputImage = imageToBeProcessed // a CIImage
imageView.image = UIImage(ciImage: filter.outputImage!)

--

--