def scale_image_to_size(image=None, bucket=None, key=None, uri=None, max_pixels=None, max_bytes=None): try: from PIL import Image if image: src_bytes = _image_byte_count(image) else: src_bytes = s3.get_object_size(bucket, key, uri) image = s3.read_pillow_image(bucket, key, uri) x, y = image.size src_pixels = x * y bytes_scalar = math.sqrt(max_bytes / src_bytes) if max_bytes else 1 pixels_scalar = math.sqrt(max_pixels / src_pixels) if max_pixels else 1 scalar = min(bytes_scalar, pixels_scalar) if scalar >= 1: return image, None else: new_x = int(scalar * x) new_y = int(scalar * y) new_image, scalar = image.resize((new_x, new_y), Image.BICUBIC), scalar if max_bytes and _image_byte_count(new_image) > max_bytes: return scale_image_to_size(image=image, max_pixels=max_pixels, max_bytes=int(max_bytes * 0.95)) else: return new_image, scalar except ImportError as e: # Simply raise the ImportError to let the user know this requires Pillow to function raise e
def render_boxes_from_objects(objects, accessor, image=None, image_uri=None, labels=None, single_image=True, color=None): # TODO: Avoid an unnecessary copy step when coming from uri if image_uri: image = s3.read_pillow_image(uri=image_uri) # Change palette mode images to RGB so that standard palette colors can be drawn on them if image.mode == 'P': image = image.convert(mode='RGB') else: image = image.copy() if isinstance(objects, collections.Mapping): annotation = accessor(objects) if labels: return render_boxes(annotation, image=image, image_uri=image_uri, color=color, color_index=lambda idx, item: _find_label_index(item, labels)) else: return render_boxes(annotation, image=image, image_uri=image_uri, color=color) elif single_image: for idx, obj in enumerate(objects): annotation = accessor(obj) if callable(color): image = render_boxes(annotation, image=image, color=lambda o_idx, e_idx, item: color(idx, e_idx, item), color_index=lambda i, item: idx) else: image = render_boxes(annotation, image=image, color_index=lambda i, item: idx) return image else: images = [] for idx, obj in enumerate(objects): annotation = accessor(obj) if callable(color): images.append(render_boxes(annotation, image=image, color=lambda e_idx, item: color(idx, e_idx, item), color_index=lambda i, item: idx)) else: images.append(render_boxes(annotation, image=image, color_index=lambda i, item: idx)) return images
def render_boxes(boxes, image=None, image_uri=None, color=None, width=None, label_size=None, label=None, annotation_filter=None, get_box=None, color_index=None): if image_uri: image = s3.read_pillow_image(uri=image_uri) # Change palette mode images to RGB so that standard palette colors can be drawn on them if image.mode == 'P': image = image.convert(mode='RGB') else: image = image.copy() if color is None: color = get_color_list() width = round(image.width / 512) + 1 if width is None else width label_size = 20 if label_size is None else label_size try: from PIL import ImageDraw, ImageFont draw = ImageDraw.Draw(image) # TODO Find a better way to pull in fonts font = ImageFont.truetype("/usr/share/fonts/dejavu/DejaVuSans.ttf", size=label_size) for idx, item in enumerate(boxes): if annotation_filter is None or annotation_filter(idx, item): # Retrieve the box coordinates from the annotation if get_box: item = get_box(idx, item) box = box_coordinates(item) # select a color to use with this box if isinstance(color, str): box_color = color elif callable(color): box_color = color(idx, item) elif color_index: # TODO: Fix array out of bounds issue box_color = color[color_index(idx, item)] else: box_color = 'green' draw.rectangle(box, outline=box_color, width=width) if label: if isinstance(label, str): text = label else: text = label(idx, item) size = draw.textsize(text, font=font, spacing=0) draw.multiline_text((box[0] - size[0] - 4, box[1] + 4), text, fill=box_color, font=font, spacing=0, align='right') return image except ImportError as e: # Simply raise the ImportError to let the user know this requires Pillow to function raise e