Mercurial > repos > tomasz-bednarz > image_tools
comparison tools/image_transforms.py @ 0:64374d852e36
Uploaded
author | tomasz-bednarz |
---|---|
date | Mon, 25 Nov 2013 21:32:12 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:64374d852e36 |
---|---|
1 """Transformations on images""" | |
2 from numpy import random | |
3 from numpy import array | |
4 from PIL import Image | |
5 from PIL import ImageDraw | |
6 from PIL import ImageOps | |
7 | |
8 def tileify(image_data, num_blocks, max_shift): | |
9 """ | |
10 Breaks image up into rectangles and shifts them a random distance | |
11 Areas not covered by the moved rectangles are the negative of | |
12 the original image | |
13 """ | |
14 width = image_data.size[0] | |
15 height = image_data.size[1] | |
16 row_block_size = round(height / num_blocks) | |
17 col_block_size = round(width / num_blocks) | |
18 negative_image = ImageOps.invert(image_data) | |
19 pixels = array(image_data) | |
20 for row in xrange(num_blocks): | |
21 inner_row_val = int(row_block_size * row) | |
22 outer_row_val = int(row_block_size * row + row_block_size) | |
23 for col in xrange(num_blocks): | |
24 inner_col_val = int(col_block_size * col) | |
25 outer_col_val = int(col_block_size * col + col_block_size) | |
26 block = pixels[ | |
27 inner_row_val:outer_row_val, | |
28 inner_col_val:outer_col_val | |
29 ] | |
30 location = calculate_random_location( | |
31 inner_row_val, | |
32 inner_col_val, | |
33 max_shift | |
34 ) | |
35 negative_image.paste(Image.fromarray(block), location) | |
36 return negative_image | |
37 | |
38 def calculate_random_location(x, y, max_shift): | |
39 """ | |
40 Calculates random location near some starting point | |
41 Inputs | |
42 x - coordinate point where 0,0 is upper left corner | |
43 y - coordinate point where 0,0 is upper left corner | |
44 max_shift - the furthest distance from the point to shift | |
45 """ | |
46 x_offset = random.random_integers(-max_shift, max_shift) | |
47 y_offset = random.random_integers(-max_shift, max_shift) | |
48 location = ( | |
49 y + y_offset, | |
50 x + x_offset | |
51 ) | |
52 return location | |
53 | |
54 def filmify_image(image_data): | |
55 """ | |
56 Makes the image look like 35mm film | |
57 Inputs: | |
58 PIL Image | |
59 Returns: | |
60 Modified image data | |
61 """ | |
62 # print 'Filming' | |
63 # Size of photo in side the film | |
64 film_size = (400, 300) | |
65 border_size = 30 | |
66 film_hole_size = (8, 10) | |
67 | |
68 filmed_image = modify_photo(image_data, film_size) | |
69 filmed_image = add_film_border(filmed_image, film_size, border_size) | |
70 | |
71 # Center strip in the border space | |
72 strip_upper_offset = int(round((border_size - film_hole_size[1])/2)) | |
73 strip_lower_offset = film_size[1] + border_size + strip_upper_offset | |
74 # Bring strip in towards the photo | |
75 offset = int(round(film_hole_size[1]/2)) | |
76 strip_upper_offset = strip_upper_offset + offset | |
77 strip_lower_offset = strip_lower_offset - offset | |
78 | |
79 place_film_strip( | |
80 filmed_image, | |
81 strip_upper_offset, | |
82 strip_lower_offset, | |
83 film_hole_size | |
84 ) | |
85 | |
86 return filmed_image | |
87 | |
88 def add_film_border(image_data, film_size, border_size): | |
89 """ | |
90 Creates a black border around the image | |
91 Inputs | |
92 image_data - image to be manipulated | |
93 film_size - size of the internal picture | |
94 border_size - how wide you want the border on the top and bottom to be | |
95 Output | |
96 image with border | |
97 """ | |
98 image_data = ImageOps.expand( | |
99 image_data, | |
100 border=border_size, | |
101 fill='black' | |
102 ) | |
103 # Crop to cut half of border from right and left of image | |
104 crop_box = ( | |
105 int(round(border_size/2)), | |
106 0, | |
107 film_size[0] + int(round(border_size * 1.5)), | |
108 film_size[1] + border_size * 2 | |
109 ) | |
110 image_data = image_data.crop(crop_box) | |
111 return image_data | |
112 | |
113 def place_film_strip(image_data, y_offset_upper, y_offset_lower, film_hole_size): | |
114 """ | |
115 Create strip of film_holes at y_offset | |
116 """ | |
117 hole_distance = 15 | |
118 left_film_buffer = 2 | |
119 for x_offset in range(left_film_buffer, image_data.size[0], hole_distance): | |
120 place_film_hole(image_data, (x_offset, y_offset_upper), film_hole_size) | |
121 place_film_hole(image_data, (x_offset, y_offset_lower), film_hole_size) | |
122 | |
123 def place_film_hole(image_data, offset, film_hole_size): | |
124 """ | |
125 Puts film hole at offset into the image provided | |
126 Inputs: | |
127 image_data - image file to have film hole pasted | |
128 offset - 2 tuple with x and y of the top left corner of film hole | |
129 film_hole_size - size of the rectangle to be made | |
130 Outputs | |
131 Original image with rectangle in location based on the offset | |
132 """ | |
133 corner_radius = 2 | |
134 film_hole_color = 'white' | |
135 film_hole = round_rectangle(film_hole_size, corner_radius, film_hole_color) | |
136 image_data.paste(film_hole, offset) | |
137 | |
138 def round_corner(radius, fill): | |
139 """ | |
140 Draw a round corner | |
141 This code came from http://nadiana.com/pil-tutorial-basic-advanced-drawing | |
142 """ | |
143 corner = Image.new('RGBA', (radius, radius), (0, 0, 0, 0)) | |
144 draw = ImageDraw.Draw(corner) | |
145 draw.pieslice((0, 0, radius * 2, radius * 2), 180, 270, fill=fill) | |
146 return corner | |
147 | |
148 def round_rectangle(size, radius, fill): | |
149 """ | |
150 Draw a rounded rectangle | |
151 This code came from http://nadiana.com/pil-tutorial-basic-advanced-drawing | |
152 """ | |
153 width, height = size | |
154 rectangle = Image.new('RGBA', size, fill) | |
155 corner = round_corner(radius, fill) | |
156 rectangle.paste(corner, (0, 0)) | |
157 # Rotate the corner and paste it | |
158 rectangle.paste(corner.rotate(90), (0, height - radius)) | |
159 rectangle.paste(corner.rotate(180), (width - radius, height - radius)) | |
160 rectangle.paste(corner.rotate(270), (width - radius, 0)) | |
161 return rectangle | |
162 | |
163 def modify_photo(image_data, film_size): | |
164 """ | |
165 Make the image grayscale and invert the colors | |
166 All manipulations for the original photo go here | |
167 """ | |
168 modified_image = ImageOps.grayscale(image_data) | |
169 # Image.ANTIALIAS is best for down sizing | |
170 modified_image = modified_image.resize(film_size, Image.ANTIALIAS) | |
171 modified_image = ImageOps.invert(modified_image) | |
172 modified_image = ImageOps.flip(modified_image) | |
173 return modified_image |