Over a million developers have joined DZone.

Simulating Depth-of-Field with Variable Bokeh in Core Image

DZone's Guide to

Simulating Depth-of-Field with Variable Bokeh in Core Image

Depth of field focuses our attention in a photograph. Read this and focus on how to fake it digitally.

· Mobile Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

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; "     }


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.

Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

core image filters ,swift ,image manipulation

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}