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
| import argparse import cv2 import glob import numpy as np import os from tqdm import tqdm from itertools import product
def parse_args(): parser = argparse.ArgumentParser("Mosaic Photo") parser.add_argument("--source-path", type=str, default='source', help="the path for all source images") parser.add_argument("--target-path", type=str, default='target', help="the path for the template photo") parser.add_argument("--output-path", type=str, default='output', help="the path for the mosaic photo") parser.add_argument("--block-size", type=int, default=20, help="the block size of each image in the mosaic image") parser.add_argument("--expand-factor", type=int, default=1, help="expand the size of the template image; 1 means " "keeping the same size as the template image") args = parser.parse_args() return args
def rename_by_date(path): """ Rename all source images by the modification time. """ all_imgs = glob.glob("{}/*.jpg".format(path)) all_cts = [] for img in all_imgs: ct = os.path.getmtime(img) all_cts.append(ct) sort_ind = np.asarray(all_cts).argsort().tolist() for i, ind in enumerate(sort_ind): os.rename(all_imgs[ind], "source/{}.jpg".format(str(i + 1).zfill(3)))
def read_source_images(source_path, block_size, expand_factor): """ Read source images and calculate the average RGB values. """ source_images = glob.glob('{}/*.jpg'.format(source_path)) resized_source_images = [] avg_colors = [] resize_size = block_size * expand_factor print("Begin reading source images") for path in tqdm(source_images): image = cv2.imread(path, cv2.IMREAD_COLOR) if image.shape[-1] != 3: continue image = cv2.resize(image, (resize_size, resize_size)) avg_rgb = np.sum(np.sum(image, axis=0), axis=0) / ( resize_size * resize_size) resized_source_images.append(image) avg_colors.append(avg_rgb) print("End reading source images") return resized_source_images, np.array(avg_colors)
def main(): opts = parse_args()
source_images, avg_colors = read_source_images( opts.source_path, opts.block_size, opts.expand_factor) assert len(source_images) > 0, "Fail to load source images" print("Successfully load {} source images".format(len(source_images)))
assert os.path.exists(opts.target_path), \ "{} does not exist".format(opts.target_path) target_imgs = glob.glob('{}/*.jpg'.format(opts.target_path)) assert len(target_imgs) > 0, "Fail to load template images" os.makedirs(opts.output_path, exist_ok=True)
output_block_size = opts.block_size * opts.expand_factor print("Begin concatenating") for target_img_path in tqdm(target_imgs): target_img = cv2.imread(target_img_path) w, h, c = target_img.shape output_img = np.zeros( [w * opts.expand_factor, h * opts.expand_factor, c], np.uint8) iterator = product( range(int(target_img.shape[0] / opts.block_size)), range(int(target_img.shape[1] / opts.block_size))) for i, j in iterator: block = target_img[ i * opts.block_size: (i + 1) * opts.block_size, j * opts.block_size: (j + 1) * opts.block_size, :] avg_rgb = np.sum(np.sum(block, axis=0), axis=0) / ( opts.block_size * opts.block_size) distances = np.linalg.norm(avg_colors - avg_rgb, axis=1) idx = np.argmin(distances) output_img[i * output_block_size: (i + 1) * output_block_size, j * output_block_size: (j + 1) * output_block_size, :] \ = source_images[idx] cv2.imwrite(target_img_path.replace(opts.target_path, opts.output_path), output_img) print("End concatenating")
if __name__ == '__main__': main()
|