-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathimage_utils.py
More file actions
146 lines (133 loc) · 5.66 KB
/
image_utils.py
File metadata and controls
146 lines (133 loc) · 5.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# From https://github.com/ageitgey/image_to_numpy/blob/master/image_to_numpy/src.py
# Altered only slightly
import PIL.Image
from PIL import Image
import PIL.ImageOps
import numpy as np
# Utility function from https://medium.com/@ageitgey/the-dumb-reason-your-fancy-computer-vision-app-isnt-working-exif-orientation-73166c7d39da
def exif_transpose(img):
"""
If an image has an Exif Orientation tag, transpose the image
accordingly.
Note: Very recent versions of Pillow have an internal version
of this function. So this is only needed if Pillow isn't at the
latest version.
:param image: The image to transpose.
:return: An image.
"""
if not img:
return img
exif_orientation_tag = 274
# Check for EXIF data (only present on some files)
if hasattr(img, "_getexif") and isinstance(img._getexif(), dict) and exif_orientation_tag in img._getexif():
exif_data = img._getexif()
orientation = exif_data[exif_orientation_tag]
# Handle EXIF Orientation
if orientation == 1:
# Normal image - nothing to do!
pass
elif orientation == 2:
# Mirrored left to right
img = img.transpose(PIL.Image.FLIP_LEFT_RIGHT)
elif orientation == 3:
# Rotated 180 degrees
img = img.rotate(180)
elif orientation == 4:
# Mirrored top to bottom
img = img.rotate(180).transpose(PIL.Image.FLIP_LEFT_RIGHT)
elif orientation == 5:
# Mirrored along top-left diagonal
img = img.rotate(-90, expand=True).transpose(PIL.Image.FLIP_LEFT_RIGHT)
elif orientation == 6:
# Rotated 90 degrees
img = img.rotate(-90, expand=True)
elif orientation == 7:
# Mirrored along top-right diagonal
img = img.rotate(90, expand=True).transpose(PIL.Image.FLIP_LEFT_RIGHT)
elif orientation == 8:
# Rotated 270 degrees
img = img.rotate(90, expand=True)
return img
def load_image_file(file, mode='RGB'):
"""
Loads an image file (.jpg, .png, etc) into a numpy array
Defaults to returning the image data as a 3-channel array of 8-bit data. That is
controlled by the mode parameter.
Supported modes:
1 (1-bit pixels, black and white, stored with one pixel per byte)
L (8-bit pixels, black and white)
RGB (3x8-bit pixels, true color)
RGBA (4x8-bit pixels, true color with transparency mask)
CMYK (4x8-bit pixels, color separation)
YCbCr (3x8-bit pixels, color video format)
I (32-bit signed integer pixels)
F (32-bit floating point pixels)
:param file: image file name or file object to load
:param mode: format to convert the image to - 'RGB' (8-bit RGB, 3 channels), 'L' (black and white)
:return: image contents as numpy array
"""
# Load the image with PIL
img = PIL.Image.open(file)
if False: #hasattr(PIL.ImageOps, 'exif_transpose'):
# Very recent versions of PIL can do exit transpose internally
img = PIL.ImageOps.exif_transpose(img)
else:
# Otherwise, do the exif transpose ourselves
img = exif_transpose(img)
#img = img.convert(mode)
return img
# From https://gist.github.com/sigilioso/2957026
def resize_and_crop_and_save(img, modified_path, size, crop_type='middle'):
"""
Resize and crop an image to fit the specified size.
args:
img: img
modified_path: path to store the modified image.
size: `(width, height)` tuple.
crop_type: can be 'top', 'middle' or 'bottom', depending on this
value, the image will cropped getting the 'top/left', 'middle' or
'bottom/right' of the image to fit the size.
raises:
Exception: if can not open the file in img_path of there is problems
to save the image.
ValueError: if an invalid `crop_type` is provided.
"""
# If height is higher we resize vertically, if not we resize horizontally
#img = Image.open(img_path)
# Get current and desired ratio for the images
img_ratio = img.size[0] / float(img.size[1])
ratio = size[0] / float(size[1])
#The image is scaled/cropped vertically or horizontally depending on the ratio
if ratio > img_ratio:
img = img.resize((size[0], round(size[0] * img.size[1] / img.size[0])),
Image.ANTIALIAS)
# Crop in the top, middle or bottom
if crop_type == 'top':
box = (0, 0, img.size[0], size[1])
elif crop_type == 'middle':
box = (0, round((img.size[1] - size[1]) / 2), img.size[0],
round((img.size[1] + size[1]) / 2))
elif crop_type == 'bottom':
box = (0, img.size[1] - size[1], img.size[0], img.size[1])
else :
raise ValueError('ERROR: invalid value for crop_type')
img = img.crop(box)
elif ratio < img_ratio:
img = img.resize((round(size[1] * img.size[0] / img.size[1]), size[1]),
Image.ANTIALIAS)
# Crop in the top, middle or bottom
if crop_type == 'top':
box = (0, 0, size[0], img.size[1])
elif crop_type == 'middle':
box = (round((img.size[0] - size[0]) / 2), 0,
round((img.size[0] + size[0]) / 2), img.size[1])
elif crop_type == 'bottom':
box = (img.size[0] - size[0], 0, img.size[0], img.size[1])
else :
raise ValueError('ERROR: invalid value for crop_type')
img = img.crop(box)
else :
img = img.resize((size[0], size[1]),
Image.ANTIALIAS)
# If the scale is the same, we do not need to crop
img.save(modified_path)