mirror of
https://github.com/wassname/IndicoIo-python.git
synced 2026-06-27 16:10:34 +08:00
93 lines
3.0 KiB
Python
93 lines
3.0 KiB
Python
"""
|
|
Image Utils
|
|
Handles preprocessing images before they are sent to the server
|
|
"""
|
|
import os.path, base64, StringIO, re, warnings
|
|
|
|
from PIL import Image
|
|
|
|
from indicoio.utils.errors import IndicoError, DataStructureException
|
|
|
|
B64_PATTERN = re.compile("^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)")
|
|
|
|
def image_preprocess(image, size=(48,48), min_axis=None, batch=False):
|
|
"""
|
|
Takes an image and prepares it for sending to the api including
|
|
resizing and image data/structure standardizing.
|
|
"""
|
|
if batch:
|
|
return [image_preprocess(img, batch=False) for img in image]
|
|
|
|
if isinstance(image, basestring):
|
|
b64_str = re.sub('^data:image/.+;base64,', '', image)
|
|
if os.path.isfile(image):
|
|
# check type of element
|
|
out_image = Image.open(image)
|
|
elif B64_PATTERN.match(b64_str) is not None:
|
|
return b64_str
|
|
else:
|
|
raise IndicoError("String provided must be a valid filepath or base64 encoded string")
|
|
|
|
elif isinstance(image, Image.Image):
|
|
out_image = image
|
|
elif type(image).__name__ == "ndarray": # image is from numpy/scipy
|
|
if "float" in str(image.dtype) and image.min() >= 0 and image.max() <= 1:
|
|
image *= 255.
|
|
try:
|
|
out_image = Image.fromarray(image.astype("uint8"))
|
|
except TypeError as e:
|
|
raise IndicoError("Please ensure the numpy array is acceptable by PIL. Values must be between 0 and 1 or between 0 and 255 in greyscale, rgb, or rgba format.")
|
|
|
|
else:
|
|
raise IndicoError("Image must be a filepath, base64 encoded string, or a numpy array")
|
|
|
|
out_image = resize_image(out_image, size, min_axis)
|
|
|
|
# convert to base64
|
|
temp_output = StringIO.StringIO()
|
|
out_image.save(temp_output, format='PNG')
|
|
temp_output.seek(0)
|
|
output_s = temp_output.read()
|
|
|
|
return base64.b64encode(output_s)
|
|
|
|
|
|
def resize_image(image, size, min_axis):
|
|
if min_axis:
|
|
min_idx, other_idx = (0,1) if image.size[0] < image.size[1] else (1,0)
|
|
aspect = image.size[other_idx]/float(image.size[min_idx])
|
|
if aspect > 10:
|
|
warnings.warn(
|
|
"An aspect ratio greater than 10:1 is not recommended",
|
|
Warning
|
|
)
|
|
size_arr = [0,0]
|
|
size_arr[min_idx] = min_axis
|
|
size_arr[other_idx] = int(min_axis * aspect)
|
|
image = image.resize(tuple(size_arr))
|
|
elif size:
|
|
image = image.resize(size)
|
|
return image
|
|
|
|
|
|
def get_list_dimensions(_list):
|
|
"""
|
|
Takes a nested list and returns the size of each dimension followed
|
|
by the element type in the list
|
|
"""
|
|
if isinstance(_list, list) or isinstance(_list, tuple):
|
|
return [len(_list)] + get_list_dimensions(_list[0])
|
|
return []
|
|
|
|
|
|
def get_element_type(_list, dimens):
|
|
"""
|
|
Given the dimensions of a nested list and the list, returns the type of the
|
|
elements in the inner list.
|
|
"""
|
|
elem = _list
|
|
for _ in xrange(len(dimens)):
|
|
elem = elem[0]
|
|
return type(elem)
|
|
|