Skip to content

Instantly share code, notes, and snippets.

@kernel1994
Created August 21, 2018 16:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kernel1994/ae930f426a99194c8aec1b4b79232bab to your computer and use it in GitHub Desktop.
Save kernel1994/ae930f426a99194c8aec1b4b79232bab to your computer and use it in GitHub Desktop.
concatenate images in vertical or horizontal.
import argparse
import numpy as np
from PIL import Image
def pad_image(image: Image, desired_size: tuple, pad_value: str='#fff') -> Image:
"""
pad image to make image in center.
Args:
image: PIL.Image:
desired_size: tuple(int): (desired width, desired height)
pad_value: int: pad color value, default #fff is white.
Return:
PIL.Image: padded image.
"""
new_im = Image.new("RGB", desired_size, color=pad_value)
# offset make sure the image always in vertical or horizontal center.
offset = (np.asarray(desired_size) - np.asarray(image.size)) // 2
new_im.paste(image, box=tuple(offset)) # 2-tuple box indicate upper left corner.
return new_im
def concat_images(mode: str, image_paths: list):
"""
concatenate images in vertical or horizontal.
Args:
mode: str: mode of concatenate, value: "v": vertical; "h": horizontal;
image_paths: list(str): image file paths.
Return:
None
Raises:
ValueError: mode value error.
"""
# list(PIL.Image)
images = [Image.open(f) for f in image_paths]
# => list(zip(*(img.size for img in images)))
# => list(zip(*((w_1, h_1), (w_2, h_2), ..., (w_n, h_n))))
# => list(zip((w_1, h_1), (w_2, h_2), ..., (w_n, h_n)))
# => [(w_1, w_2, ..., w_n), (h_1, h_2, ..., h_n)]
widths, heights = list(zip(*(img.size for img in images)))
for img in images:
print('{0} size: {1} * {2} px'.format(img.filename, img.size[0], img.size[1]))
if mode == 'v':
# vertical mode, img_1 is in the above of img_2
# the output width is max of all images' width
# the output height is sum of all images' height
output_width = max(widths)
output_height = sum(heights)
print('output size: {0} * {1} px'.format(output_width, output_height))
# 'resize' or pad image to size (output_width, original_height)
ary = np.vstack([np.asarray(pad_image(img, (output_width, img.size[1]))) for img in images])
elif mode == 'h':
# horizontal mode, img_1 is in the left of img_2
# the output width is sum of all images' width
# the output height is max of all images' height
output_width = sum(widths)
output_height = max(heights)
print('output size: {0} * {1} px'.format(output_width, output_height))
# 'resize' or pad image to size (original_width, output_height)
ary = np.hstack([np.asarray(pad_image(img, (img.size[0], output_height))) for img in images])
else:
raise ValueError(r'-m {v, h}, the mode must be h or v.')
output_image = Image.fromarray(ary, mode='RGB')
output_image.save('o.jpg')
def main():
parser = argparse.ArgumentParser(description='concatenate images.')
# first two arguments are names of args
# choices, the permitted values
parser.add_argument('-m', '--mode', nargs=1, choices=['v', 'h'],
help='mode of concatenate type. (value: "v": vertical; "h": horizontal;).')
# nargs, + present 1 or more args
parser.add_argument('-f', '--files', nargs='+', help='images to be jointed.')
# action='store_true', if set -v, value is ture
parser.add_argument('-v', '--verbose', action='store_true', help='increase output verbosity.')
args = parser.parse_args()
# the type of arg value are list
mode = args.mode[0]
files = args.files
if args.verbose:
print(args)
concat_images(mode, files)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment