diff tools/image_transforms.py @ 0:64374d852e36

Uploaded
author tomasz-bednarz
date Mon, 25 Nov 2013 21:32:12 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/image_transforms.py	Mon Nov 25 21:32:12 2013 -0500
@@ -0,0 +1,173 @@
+"""Transformations on images"""
+from numpy import random
+from numpy import array
+from PIL import Image
+from PIL import ImageDraw
+from PIL import ImageOps
+
+def tileify(image_data, num_blocks, max_shift):
+    """
+    Breaks image up into rectangles and shifts them a random distance
+    Areas not covered by the moved rectangles are the negative of
+    the original image
+    """
+    width = image_data.size[0]
+    height = image_data.size[1]
+    row_block_size = round(height / num_blocks)
+    col_block_size = round(width / num_blocks)
+    negative_image = ImageOps.invert(image_data)
+    pixels = array(image_data)
+    for row in xrange(num_blocks):
+        inner_row_val = int(row_block_size * row)
+        outer_row_val = int(row_block_size * row + row_block_size)
+        for col in xrange(num_blocks):
+            inner_col_val = int(col_block_size * col)
+            outer_col_val = int(col_block_size * col + col_block_size)
+            block = pixels[
+                inner_row_val:outer_row_val,
+                inner_col_val:outer_col_val
+            ]
+            location = calculate_random_location(
+                inner_row_val,
+                inner_col_val,
+                max_shift
+            )
+            negative_image.paste(Image.fromarray(block), location)
+    return negative_image
+
+def calculate_random_location(x, y, max_shift):
+    """
+    Calculates random location near some starting point
+    Inputs
+        x - coordinate point where 0,0 is upper left corner
+        y - coordinate point where 0,0 is upper left corner
+        max_shift - the furthest distance from the point to shift
+    """
+    x_offset = random.random_integers(-max_shift, max_shift)
+    y_offset = random.random_integers(-max_shift, max_shift)
+    location = (
+        y + y_offset,
+        x + x_offset
+    )
+    return location
+
+def filmify_image(image_data):
+    """
+    Makes the image look like 35mm film
+    Inputs:
+        PIL Image
+    Returns:
+        Modified image data
+    """
+    # print 'Filming'
+    # Size of photo in side the film
+    film_size = (400, 300)
+    border_size = 30
+    film_hole_size = (8, 10)
+
+    filmed_image = modify_photo(image_data, film_size)
+    filmed_image = add_film_border(filmed_image, film_size, border_size)
+
+    # Center strip in the border space
+    strip_upper_offset = int(round((border_size - film_hole_size[1])/2))
+    strip_lower_offset = film_size[1] + border_size + strip_upper_offset
+    # Bring strip in towards the photo
+    offset = int(round(film_hole_size[1]/2))
+    strip_upper_offset = strip_upper_offset + offset
+    strip_lower_offset = strip_lower_offset - offset
+
+    place_film_strip(
+        filmed_image,
+        strip_upper_offset,
+        strip_lower_offset,
+        film_hole_size
+    )
+
+    return filmed_image
+
+def add_film_border(image_data, film_size, border_size):
+    """
+    Creates a black border around the image
+    Inputs
+        image_data - image to be manipulated
+        film_size - size of the internal picture
+        border_size - how wide you want the border on the top and bottom to be
+    Output
+        image with border
+    """
+    image_data = ImageOps.expand(
+        image_data,
+        border=border_size,
+        fill='black'
+    )
+    # Crop to cut half of border from right and left of image
+    crop_box = (
+        int(round(border_size/2)),
+        0,
+        film_size[0] + int(round(border_size * 1.5)),
+        film_size[1] + border_size * 2
+    )
+    image_data = image_data.crop(crop_box)
+    return image_data
+
+def place_film_strip(image_data, y_offset_upper, y_offset_lower, film_hole_size):
+    """
+    Create strip of film_holes at y_offset
+    """
+    hole_distance = 15
+    left_film_buffer = 2
+    for x_offset in range(left_film_buffer, image_data.size[0], hole_distance):
+        place_film_hole(image_data, (x_offset, y_offset_upper), film_hole_size)
+        place_film_hole(image_data, (x_offset, y_offset_lower), film_hole_size)
+
+def place_film_hole(image_data, offset, film_hole_size):
+    """
+    Puts film hole at offset into the image provided
+    Inputs:
+        image_data - image file to have film hole pasted
+        offset - 2 tuple with x and y of the top left corner of film hole
+        film_hole_size - size of the rectangle to be made
+    Outputs
+        Original image with rectangle in location based on the offset
+    """
+    corner_radius = 2
+    film_hole_color = 'white'
+    film_hole = round_rectangle(film_hole_size, corner_radius, film_hole_color)
+    image_data.paste(film_hole, offset)
+
+def round_corner(radius, fill):
+    """
+    Draw a round corner
+    This code came from http://nadiana.com/pil-tutorial-basic-advanced-drawing
+    """
+    corner = Image.new('RGBA', (radius, radius), (0, 0, 0, 0))
+    draw = ImageDraw.Draw(corner)
+    draw.pieslice((0, 0, radius * 2, radius * 2), 180, 270, fill=fill)
+    return corner
+
+def round_rectangle(size, radius, fill):
+    """
+    Draw a rounded rectangle
+    This code came from http://nadiana.com/pil-tutorial-basic-advanced-drawing
+    """
+    width, height = size
+    rectangle = Image.new('RGBA', size, fill)
+    corner = round_corner(radius, fill)
+    rectangle.paste(corner, (0, 0))
+    # Rotate the corner and paste it
+    rectangle.paste(corner.rotate(90), (0, height - radius))
+    rectangle.paste(corner.rotate(180), (width - radius, height - radius))
+    rectangle.paste(corner.rotate(270), (width - radius, 0))
+    return rectangle
+
+def modify_photo(image_data, film_size):
+    """
+    Make the image grayscale and invert the colors
+    All manipulations for the original photo go here
+    """
+    modified_image = ImageOps.grayscale(image_data)
+    # Image.ANTIALIAS is best for down sizing
+    modified_image = modified_image.resize(film_size, Image.ANTIALIAS)
+    modified_image = ImageOps.invert(modified_image)
+    modified_image = ImageOps.flip(modified_image)
+    return modified_image