Focus on faces

Selects an image at random from the Tribune collection in the State Library of NSW.

In [ ]:
# This notebook is intended to be run in Appmode...

import cv2
import pandas as pd
import os
from urllib.parse import urlparse
import requests
from IPython.display import display, HTML
import copy
from PIL import Image
In [ ]:
# Link to the facial detection data file
face_cl = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# Load the face frequency data file
df = pd.read_csv('faces_per_image.csv')


def select_image(min_faces=20):
    '''
    Select a random image with the minimum number of faces.
    '''
    row = df.loc[df['faces'] > min_faces].sample(1)
    return row.iloc[0]['image']


def download_image(img_id, img_url):
    '''
    Download and save the specified image.
    '''
    current_dir = os.getcwd()
    os.makedirs(os.path.join(current_dir, 'fades'), exist_ok=True)
    filename = os.path.join(current_dir, 'fades', '{}-end.jpg'.format(img_id))
    response = requests.get(img_url, stream=True)
    with open(filename, 'wb') as fd:
        for chunk in response.iter_content(chunk_size=128):
            fd.write(chunk)
    return filename 


def detect_faces(img_id, img_file):
    '''
    Use OpenCV to find faces.
    Create a new version of the image with JUST the faces.
    '''
    faces = []
    f = 1
    os.makedirs('faces', exist_ok=True)
    # print('Processing {}'.format(img_file))
    try:
        image = cv2.imread(img_file)
        # Create a greyscale copy for face detection
        grey = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
        # Find faces!
        # Try adjusting scaleFactor and minNeighbors if results aren't what you expect.
        faces = face_cl.detectMultiScale(grey, scaleFactor=1.3, minNeighbors=4, minSize=(50, 50))
    except cv2.error:
        raise
    else:
        img = Image.open(img_file)
        img_faces = Image.new('RGB', img.size, 'white')
        for (x, y, w, h) in faces:
            face = img.crop((x, y, x+w, y+h))
            img_faces.paste(face, (x, y, x+w, y+h))
        img_faces.save('fades/{}-start.jpg'.format(img_id))


def create_face_fade(img_id=None, min_faces=20):
    '''
    Generates a simple animated thing-y.
    Starts with just the faces, click and the rest of the photos fades in.
    '''
    if img_id:
        img = '{}.jpg'.format(img_id)
    else:
        img = select_image(min_faces)
        img_id = img[:-4]
    img_url = 'https://s3-ap-southeast-2.amazonaws.com/wraggetribune/images/{0}'.format(img)
    img_file = download_image(img_id, img_url)
    faces = detect_faces(img_id, img_file)
    html = '<div style="background-image: url(\'fades/{0}-start.jpg\'); background-repeat: no-repeat; background-size: cover;"><img style="opacity: 0; transition: opacity 5s linear;" onclick="this.style.opacity=1" src="fades/{0}-end.jpg"></div>'.format(img_id)
    html += '<br><a target="_blank" href="http://digital.sl.nsw.gov.au/delivery/DeliveryManagerServlet?dps_pid={}&embedded=true&toolbar=false">More details at SLNSW</a><br>'.format(img_id)
    display(HTML(html))
In [ ]:
create_face_fade(min_faces=100)

Click on the faces to reveal more.

Reload the page for another photo.

In [ ]: