Slide 1

Slide 1 text

Instagram Filters in 15 Lines of Python Michele Pratusevich By day: computer vision researcher at Amazon By night: maintainer of Practice Python blog Reach me: [email protected] @practice_python practicepython.org These slides, if you want to follow along: I have no affiliation with Instagram, and the content presented is all my own. www.practicepython.org/pycon2017slides

Slide 2

Slide 2 text

Our goal The (now-defunct) Gotham Filter And we will get there in 15 (compact) lines (eventually). Yes, yes, the real Gotham filter is black-and-white, but this is similar and in color!

Slide 3

Slide 3 text

Our path 1. Image basics 2. Basic building blocks of Instagram filters 3. The Gotham filter 4. The code

Slide 4

Slide 4 text

Loading an image import skimage from skimage import io original_image = skimage.io.imread("skyline.jpg")

Slide 5

Slide 5 text

What is an image? (R, G, B) original_image = skimage.img_as_float(original_image)

Slide 6

Slide 6 text

What is an image? We want to look at each channel (red, green, or blue) separately: Can then merge the channels back into an image: def split_image_into_channels(image): red_channel = image[:, :, 0] green_channel = image[:, :, 1] blue_channel = image[:, :, 2] return red_channel, green_channel, blue_channel def merge_channels(red_channel, green_channel, blue_channel): return np.stack([red_channel, green_channel, blue_channel], axis=2) r, g, b = split_image_into_channels(original_image) im = merge_channels(r, g, b)

Slide 7

Slide 7 text

Image histograms An image histogram (like you see in Gimp or Photoshop) is a way to visualize how many of each pixel value exists in a channel.

Slide 8

Slide 8 text

Our path 1. Image basics 2. Basic building blocks of Instagram filters 3. The Gotham filter 4. The code

Slide 9

Slide 9 text

Components of an Instagram filter 1. Sharpening and blurring 2. Channel interpolation

Slide 10

Slide 10 text

Sharpening and blurring To blur an image, we use a Gaussian blur. Replace each pixel with a weighted sum of the neighboring pixels. from skimage import filters blurred = skimage.filters.gaussian(image, sigma=10, multichannel=True)

Slide 11

Slide 11 text

Blurring example

Slide 12

Slide 12 text

Sharpening and blurring To sharpen an image, just subtract out the blurry bits! But make sure to add enough of the regular image back. import numpy as np def sharpen(image, a, b, sigma=10): blurred = skimage.filters.gaussian(image, sigma=sigma, multichannel=True) sharper = np.clip(image * a - blurred * b, 0, 1.0) return sharper

Slide 13

Slide 13 text

Sharpening example

Slide 14

Slide 14 text

Channel interpolation Take the histogram we were visualizing earlier. We are just going to stretch and squeeze it. In histogram space (say on the red channel): So what does this mean in image space?

Slide 15

Slide 15 text

Channel interpolation on images The transformation gets applied to every pixel.

Slide 16

Slide 16 text

Enough already, show me the code! We apply this to every single pixel. def channel_adjust(channel, values): # preserve the original size, so we can reconstruct at the end orig_size = channel.shape # flatten the image into a single array flat_channel = channel.flatten() # this magical numpy function takes the values in flat_channel # and maps it from its range in [0, 1] to its new squeezed and # stretched range adjusted = np.interp(flat_channel, np.linspace(0, 1, len(values)), values) # put back into the original image shape return adjusted.reshape(orig_size)

Slide 17

Slide 17 text

Code to image r, g, b = split_image_into_channels(original_image) r_interp = channel_adjust(r, [0, 0.8, 1.0]) new_image = merge_channels(r_interp, g, b)

Slide 18

Slide 18 text

Our path 1. Image basics 2. Basic building blocks of Instagram filters 3. The Gotham filter 4. The code

Slide 19

Slide 19 text

The Gotham Filter The (now-defunct) Gotham filter from Instagram is like this: 1. A mid-tone contrast boost 2. Make the blacks a little bluer 3. A small sharpening 4. A boost in blue channel for lower mid-tones 5. A decrease in blue channel for upper mid-tones

Slide 20

Slide 20 text

1. Mid-tone contrast boost. r, g, b = split_image_into_channels(original_image) r_boost_lower = channel_adjust(r, [0, 0.05, 0.1, 0.2, 0.3, 0.5, 0.7, 0.8, 0.9, 0.95, 1.0]) r_boost_img = merge_channels(r_boost_lower, g, b)

Slide 21

Slide 21 text

2. Make the blacks a little bluer. bluer_blacks = merge_channels(r_boost_lower, g, np.clip(b + 0.03, 0, 1.0))

Slide 22

Slide 22 text

3. Sharpen the image. sharper = sharpen(bluer_blacks, 1.3, 0.3)

Slide 23

Slide 23 text

4 + 5. A boost in blue channel for lower mid-tones and decrease in blue channel for upper mid-tones. r, g, b = split_image_into_channels(sharper) b_adjusted = channel_adjust(b, [0, 0.047, 0.118, 0.251, 0.318, 0.392, 0.42, 0.439, 0.475, 0.561, 0.58, 0.627, 0.671, 0.73 3, 0.847, 0.925, 1]) gotham = merge_channels(r, g, b_adjusted)

Slide 24

Slide 24 text

Voila!

Slide 25

Slide 25 text

Our path 1. Image basics 2. Basic building blocks of Instagram filters 3. The Gotham filter 4. The code

Slide 26

Slide 26 text

As promised, 15 lines Not including image loading and imports. def channel_adjust(channel, values): orig_size = channel.shape flat_channel = channel.flatten() adjusted = np.interp(flat_channel, np.linspace(0, 1, len(values)), values) return adjusted.reshape(orig_size) r = original_image[:, :, 0] b = original_image[:, :, 2] r_boost_lower = channel_adjust(r, [0, 0.05, 0.1, 0.2, 0.3, 0.5, 0.7, 0.8, 0.9, 0.95, 1.0]) b_more = np.clip(b + 0.03, 0, 1.0) merged = np.stack([r_boost_lower, original_image[:, :, 1], b_more], axis=2) blurred = skimage.filters.gaussian(merged, sigma=10, multichannel=True) final = np.clip(merged * 1.3 - blurred * 0.3, 0, 1.0) b = final[:, :, 2] b_adjusted = channel_adjust(b, [0, 0.047, 0.118, 0.251, 0.318, 0.392, 0.42, 0.439, 0.475, 0.561, 0.58, 0.627, 0.671, 0.73 3, 0.847, 0.925, 1]) final[:, :, 2] = b_adjusted

Slide 27

Slide 27 text

Contact me Twitter: @practice_python Practice Python: Email: Learn more These slides: A blog post with a previous version of this talk: Instagram filters in Photoshop: Scikit-image documentation www.practicepython.org/pycon2017slides http://www.practicepython.org/blog/2016/12/20/instagram-filters-python.html https://99designs.com/blog/tips/instagram-photo-effect/ http://practicepython.org [email protected]