Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Michele Pratusevich - Instagram Filters in 15 L...

Michele Pratusevich - Instagram Filters in 15 Lines of Python

Images tell stories, and we love Instagram filters because they give emotion to our images. Do you want to explore what makes up Instagram filters? In this talk, we will talk about the basic elements of Instagram filters and implement them in Python. The staple libraries we will use are scikit-image and numpy - matplotlib and jupyter notebooks for plotting and interactivity. In the end, we will implement the (now-defunct) Gotham Instagram filter in 15 lines of Python (not including imports). Throughout the process, there will be many pretty pictures.

https://us.pycon.org/2017/schedule/presentation/485/

PyCon 2017

May 21, 2017
Tweet

More Decks by PyCon 2017

Other Decks in Programming

Transcript

  1. 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
  2. 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!
  3. Our path 1. Image basics 2. Basic building blocks of

    Instagram filters 3. The Gotham filter 4. The code
  4. 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)
  5. 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.
  6. Our path 1. Image basics 2. Basic building blocks of

    Instagram filters 3. The Gotham filter 4. The code
  7. 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)
  8. 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
  9. 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?
  10. 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)
  11. 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)
  12. Our path 1. Image basics 2. Basic building blocks of

    Instagram filters 3. The Gotham filter 4. The code
  13. 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
  14. 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)
  15. 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)
  16. Our path 1. Image basics 2. Basic building blocks of

    Instagram filters 3. The Gotham filter 4. The code
  17. 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
  18. 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]