resize_images_to_resolution.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import glob
  2. import os
  3. import cv2
  4. import argparse
  5. import shutil
  6. import math
  7. from PIL import Image
  8. import numpy as np
  9. def resize_images(src_img_folder, dst_img_folder, max_resolution="512x512", divisible_by=2, interpolation=None, save_as_png=False, copy_associated_files=False):
  10. # Split the max_resolution string by "," and strip any whitespaces
  11. max_resolutions = [res.strip() for res in max_resolution.split(',')]
  12. # # Calculate max_pixels from max_resolution string
  13. # max_pixels = int(max_resolution.split("x")[0]) * int(max_resolution.split("x")[1])
  14. # Create destination folder if it does not exist
  15. if not os.path.exists(dst_img_folder):
  16. os.makedirs(dst_img_folder)
  17. # Select interpolation method
  18. if interpolation == 'lanczos4':
  19. cv2_interpolation = cv2.INTER_LANCZOS4
  20. elif interpolation == 'cubic':
  21. cv2_interpolation = cv2.INTER_CUBIC
  22. else:
  23. cv2_interpolation = cv2.INTER_AREA
  24. # Iterate through all files in src_img_folder
  25. img_exts = (".png", ".jpg", ".jpeg", ".webp", ".bmp") # copy from train_util.py
  26. for filename in os.listdir(src_img_folder):
  27. # Check if the image is png, jpg or webp etc...
  28. if not filename.endswith(img_exts):
  29. # Copy the file to the destination folder if not png, jpg or webp etc (.txt or .caption or etc.)
  30. shutil.copy(os.path.join(src_img_folder, filename), os.path.join(dst_img_folder, filename))
  31. continue
  32. # Load image
  33. # img = cv2.imread(os.path.join(src_img_folder, filename))
  34. image = Image.open(os.path.join(src_img_folder, filename))
  35. if not image.mode == "RGB":
  36. image = image.convert("RGB")
  37. img = np.array(image, np.uint8)
  38. base, _ = os.path.splitext(filename)
  39. for max_resolution in max_resolutions:
  40. # Calculate max_pixels from max_resolution string
  41. max_pixels = int(max_resolution.split("x")[0]) * int(max_resolution.split("x")[1])
  42. # Calculate current number of pixels
  43. current_pixels = img.shape[0] * img.shape[1]
  44. # Check if the image needs resizing
  45. if current_pixels > max_pixels:
  46. # Calculate scaling factor
  47. scale_factor = max_pixels / current_pixels
  48. # Calculate new dimensions
  49. new_height = int(img.shape[0] * math.sqrt(scale_factor))
  50. new_width = int(img.shape[1] * math.sqrt(scale_factor))
  51. # Resize image
  52. img = cv2.resize(img, (new_width, new_height), interpolation=cv2_interpolation)
  53. else:
  54. new_height, new_width = img.shape[0:2]
  55. # Calculate the new height and width that are divisible by divisible_by (with/without resizing)
  56. new_height = new_height if new_height % divisible_by == 0 else new_height - new_height % divisible_by
  57. new_width = new_width if new_width % divisible_by == 0 else new_width - new_width % divisible_by
  58. # Center crop the image to the calculated dimensions
  59. y = int((img.shape[0] - new_height) / 2)
  60. x = int((img.shape[1] - new_width) / 2)
  61. img = img[y:y + new_height, x:x + new_width]
  62. # Split filename into base and extension
  63. new_filename = base + '+' + max_resolution + ('.png' if save_as_png else '.jpg')
  64. # Save resized image in dst_img_folder
  65. # cv2.imwrite(os.path.join(dst_img_folder, new_filename), img, [cv2.IMWRITE_JPEG_QUALITY, 100])
  66. image = Image.fromarray(img)
  67. image.save(os.path.join(dst_img_folder, new_filename), quality=100)
  68. proc = "Resized" if current_pixels > max_pixels else "Saved"
  69. print(f"{proc} image: {filename} with size {img.shape[0]}x{img.shape[1]} as {new_filename}")
  70. # If other files with same basename, copy them with resolution suffix
  71. if copy_associated_files:
  72. asoc_files = glob.glob(os.path.join(src_img_folder, base + ".*"))
  73. for asoc_file in asoc_files:
  74. ext = os.path.splitext(asoc_file)[1]
  75. if ext in img_exts:
  76. continue
  77. for max_resolution in max_resolutions:
  78. new_asoc_file = base + '+' + max_resolution + ext
  79. print(f"Copy {asoc_file} as {new_asoc_file}")
  80. shutil.copy(os.path.join(src_img_folder, asoc_file), os.path.join(dst_img_folder, new_asoc_file))
  81. def setup_parser() -> argparse.ArgumentParser:
  82. parser = argparse.ArgumentParser(
  83. description='Resize images in a folder to a specified max resolution(s) / 指定されたフォルダ内の画像を指定した最大画像サイズ(面積)以下にアスペクト比を維持したままリサイズします')
  84. parser.add_argument('src_img_folder', type=str, help='Source folder containing the images / 元画像のフォルダ')
  85. parser.add_argument('dst_img_folder', type=str, help='Destination folder to save the resized images / リサイズ後の画像を保存するフォルダ')
  86. parser.add_argument('--max_resolution', type=str,
  87. help='Maximum resolution(s) in the format "512x512,384x384, etc, etc" / 最大画像サイズをカンマ区切りで指定 ("512x512,384x384, etc, etc" など)', default="512x512,384x384,256x256,128x128")
  88. parser.add_argument('--divisible_by', type=int,
  89. help='Ensure new dimensions are divisible by this value / リサイズ後の画像のサイズをこの値で割り切れるようにします', default=1)
  90. parser.add_argument('--interpolation', type=str, choices=['area', 'cubic', 'lanczos4'],
  91. default='area', help='Interpolation method for resizing / リサイズ時の補完方法')
  92. parser.add_argument('--save_as_png', action='store_true', help='Save as png format / png形式で保存')
  93. parser.add_argument('--copy_associated_files', action='store_true',
  94. help='Copy files with same base name to images (captions etc) / 画像と同じファイル名(拡張子を除く)のファイルもコピーする')
  95. return parser
  96. def main():
  97. parser = setup_parser()
  98. args = parser.parse_args()
  99. resize_images(args.src_img_folder, args.dst_img_folder, args.max_resolution,
  100. args.divisible_by, args.interpolation, args.save_as_png, args.copy_associated_files)
  101. if __name__ == '__main__':
  102. main()