| | |
| | |
| | """ |
| | |
| | @author: Tu Bui @surrey.ac.uk |
| | """ |
| | from __future__ import absolute_import |
| | from __future__ import division |
| | from __future__ import print_function |
| | from scipy import fftpack |
| | import sys, os |
| | from pathlib import Path |
| | import numpy as np |
| | import random |
| | import glob |
| | import json |
| | import time |
| | import importlib |
| | import pandas as pd |
| | from tqdm import tqdm |
| | |
| | |
| | import matplotlib |
| | |
| | import matplotlib.pyplot as plt |
| | import matplotlib.patches as mpatches |
| | from PIL import Image, ImageDraw, ImageFont |
| | cmap = plt.get_cmap("tab10") |
| | cmap = plt.rcParams['axes.prop_cycle'].by_key()['color'] |
| |
|
| | FONT = '/vol/research/tubui1/_base/utils/FreeSans.ttf' |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | def make_grid(array_list, gsize=(3,3)): |
| | """ |
| | make a grid image from a list of image array (RGB) |
| | return: array RGB |
| | """ |
| | assert len(gsize)==2 and gsize[0]*gsize[1]==len(array_list) |
| | h,w,c = array_list[0].shape |
| | out = np.array(array_list).reshape(gsize[0], gsize[1], h, w, c).transpose(0, 2, 1, 3, 4).reshape(gsize[0]*h, gsize[1]*w, c) |
| | return out |
| |
|
| | def collage(im_list, size=None, pad=0, color=255): |
| | """ |
| | generalised function of make_grid() |
| | work on PIL/numpy images of arbitrary size |
| | """ |
| | if size is None: |
| | size=(1, len(im_list)) |
| | assert len(size)==2 |
| | if isinstance(im_list[0], np.ndarray): |
| | im_list = [Image.fromarray(im) for im in im_list] |
| | h, w = size |
| | n = len(im_list) |
| | canvas = [] |
| | for i in range(h): |
| | start, end = i*w, min((i+1)*w, n) |
| | row = combine_horz(im_list[start:end], pad, color) |
| | canvas.append(row) |
| | canvas = combine_vert(canvas, pad, color) |
| | return canvas |
| |
|
| | def combine_horz(pil_ims, pad=0, c=255): |
| | """ |
| | Combines multiple pil_ims into a single side-by-side PIL image object. |
| | """ |
| | widths, heights = zip(*(i.size for i in pil_ims)) |
| | total_width = sum(widths) + (len(pil_ims)-1) * pad |
| | max_height = max(heights) |
| | color = (c,c,c) |
| | new_im = Image.new('RGB', (total_width, max_height), color) |
| | x_offset = 0 |
| | for im in pil_ims: |
| | new_im.paste(im, (x_offset,0)) |
| | x_offset += (im.size[0] + pad) |
| | return new_im |
| |
|
| |
|
| | def combine_vert(pil_ims, pad=0, c=255): |
| | """ |
| | Combines multiple pil_ims into a single vertical PIL image object. |
| | """ |
| | widths, heights = zip(*(i.size for i in pil_ims)) |
| | max_width = max(widths) |
| | total_height = sum(heights) + (len(pil_ims)-1)*pad |
| | color = (c,c,c) |
| | new_im = Image.new('RGB', (max_width, total_height), color) |
| | y_offset = 0 |
| | for im in pil_ims: |
| | new_im.paste(im, (0,y_offset)) |
| | y_offset += (im.size[1] + pad) |
| | return new_im |
| |
|
| | def make_text_image(img_shape=(100,20), text='hello', font_path=FONT, offset=(0,0), font_size=16): |
| | """ |
| | make a text image with given width/height and font size |
| | Args: |
| | img_shape, offset tuple (width, height) |
| | font_path path to font file (TrueType) |
| | font_size max font size, actual may smaller |
| | |
| | Return: |
| | pil image |
| | """ |
| | im = Image.new('RGB', tuple(img_shape), (255,255,255)) |
| | draw = ImageDraw.Draw(im) |
| |
|
| | def get_font_size(max_font_size): |
| | font = ImageFont.truetype(font_path, max_font_size) |
| | text_size = font.getsize(text) |
| | start_w = int((img_shape[0] - text_size[0]) / 2) |
| | start_h = int((img_shape[1] - text_size[1])/2) |
| | if start_h <0 or start_w < 0: |
| | return get_font_size(max_font_size-2) |
| | else: |
| | return font, (start_w, start_h) |
| | font, pos = get_font_size(font_size) |
| | pos = (pos[0]+offset[0], pos[1]+offset[1]) |
| | draw.text(pos, text, font=font, fill=0) |
| | return im |
| |
|
| |
|
| | def log_scale(array, epsilon=1e-12): |
| | """Log scale the input array. |
| | """ |
| | array = np.abs(array) |
| | array += epsilon |
| | array = np.log(array) |
| | return array |
| |
|
| | def dct2(array): |
| | """2D DCT""" |
| | array = fftpack.dct(array, type=2, norm="ortho", axis=0) |
| | array = fftpack.dct(array, type=2, norm="ortho", axis=1) |
| | return array |
| |
|
| | def idct2(array): |
| | """inverse 2D DCT""" |
| | array = fftpack.idct(array, type=2, norm="ortho", axis=0) |
| | array = fftpack.idct(array, type=2, norm="ortho", axis=1) |
| | return array |
| |
|
| |
|
| | class DCT(object): |
| | def __init__(self, log=True): |
| | self.log = log |
| |
|
| | def __call__(self, x): |
| | x = np.array(x) |
| | x = dct2(x) |
| | if self.log: |
| | x = log_scale(x) |
| | |
| | x = np.clip((x - x.min())/(x.max() - x.min()) * 255, 0, 255).astype(np.uint8) |
| | return Image.fromarray(x) |
| |
|
| | def __repr__(self): |
| | s = f'(Discrete Cosine Transform, logarithm={self.log})' |
| | return self.__class__.__name__ + s |