![]() |
Circular Masked Variable Bokeh |
![]() |
Hexagonal Masked Variable Bokeh |
Continuing on from my recent post on simulating bokeh with Metal Performance Shaders, I thought it would be interesting to create a filter similar to Core Image's built-in Masked Variable Blur but applying bokeh intensity rather than blur based on the luminance of a second image.
I've created two filters, MaskedVariableHexagonalBokeh and MaskedVariableCircularBokeh to do just this. Both have an inputBokehMask attribute which is of type CIImage. Where the inputBokehMask is black no effect is applied, and where it is white, the maximum effect is applied:
If you're wondering about the photograph: yes, we do have a shop in London that sells sterling silver lids for your mustard, Marmite and other condiment jars.
To produce these filters, I had to write my own dilate operator in Core Image Kernel Language. The approach is very similar to a masked variable box blur I wrote for my book, Core Image for Swift.
In a nutshell, my kernel iterates over a pixel's neighbours. While a box blur averages out the values of those neighbouring pixels, a dilate simply returns the brightest pixel. The great thing about writing my own dilate is that I can code in a formula for the probe rather than passing in an array. That formula is based on the luminance of the bokeh mask image - allowing for a variable bokeh intensity at each pixel.
The only practical difference between the circular and hexagonal versions of my masked variable bokeh is that formula. My base class is the circular version and the hexagonal version simply overrides withinProbe() which is used in the construction of the CIKL:
// MaskedVariableHexagonalBokeh
override func withinProbe() -> String
{
return "float withinProbe = ((xx > h || yy > v * 2.0) ? 1.0 : ((2.0 * v * h - v * xx - h * yy) >= 0.0) ? 0.0 : 1.0);"
}
// MaskedVariableCircularBokeh
func withinProbe() -> String
{
return "float withinProbe = length(vec2(xx, yy)) < float(radius) ? 0.0 : 1.0; "
}
Easy!
With the clever use of a mask, these filters are excellent for simulating depth-of-field or tilt shift with a more lens-like look that a simple Gaussian blur.
With the clever use of a mask, these filters are excellent for simulating depth-of-field or tilt shift with a more lens-like look that a simple Gaussian blur.
Both of these filters have been added to Filterpedia. I've also added a radial gradient image to Filterpedia which is a great way to illustrate the effect of these filters.
Core Image for Swift
If you'd like to learn more about Core Image, may I recommend my book, Core Image for Swift.Core Image for Swift is available from both Apple's iBooks Store or, as a PDF, from Gumroad. IMHO, the iBooks version is better, especially as it contains video assets which the PDF version doesn't.
Add a comment