Add resize contrib module

pull/1347/head
Piero Toffanin 2021-09-13 17:06:51 +00:00
rodzic 88ab373f12
commit 2d74aa9f57
4 zmienionych plików z 206 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,16 @@
# Resize
Resize a dataset (and optional GCP file).
Resizes images, keeps Exif data. The EXIF width and height attributes will be updated accordingly also. ODM GCP files are scaled also.
Usage:
```
pip install -r requirements.txt
python3 resize.py -i images/ -o resized/ 25%
python3 resize.py -i images/1.JPG -o resized.JPG 25%
python3 resize.py -i gcp_list.txt -o resized_gcp_list.txt
```
Originally forked from https://github.com/pierotofy/exifimageresize

Wyświetl plik

@ -0,0 +1,2 @@
Pillow==8.0.1
piexif==1.1.2

Wyświetl plik

@ -0,0 +1,169 @@
import argparse
import os
import glob
import shutil
from PIL import Image
import piexif
import multiprocessing
from multiprocessing.pool import ThreadPool
import sys
sys.path.append("../../")
from opendm.gcp import GCPFile
parser = argparse.ArgumentParser(description='Exif Image Resize')
parser.add_argument('--input', '-i',
metavar='<path>',
required=True,
help='Path to input image/GCP or image folder')
parser.add_argument('--output', '-o',
metavar='<path>',
required=True,
help='Path to output image/GCP or image folder')
parser.add_argument('--force', '-f',
action='store_true',
default=False,
help='Overwrite results')
parser.add_argument('amount',
metavar='<pixel|percentage%>',
type=str,
help='Pixel of largest side or percentage to resize images by')
args = parser.parse_args()
def die(msg):
print(msg)
exit(1)
class nonloc:
errors = 0
def resize_image(image_path, out_path, resize_to, out_path_is_file=False):
"""
:param image_path: path to the image
:param out_path: path to the output directory or file
:param resize_to: percentage ("perc%") or pixels
"""
try:
im = Image.open(image_path)
path, ext = os.path.splitext(image_path)
if out_path_is_file:
resized_image_path = out_path
else:
resized_image_path = os.path.join(out_path, os.path.basename(image_path))
width, height = im.size
max_side = max(width, height)
if isinstance(resize_to, str) and resize_to.endswith("%"):
ratio = float(resize_to[:-1]) / 100.0
else:
ratio = float(resize_to) / float(max_side)
resized_width = int(width * ratio)
resized_height = int(height * ratio)
im.thumbnail((resized_width, resized_height), Image.LANCZOS)
driver = ext[1:].upper()
if driver == 'JPG':
driver = 'JPEG'
if 'exif' in im.info:
exif_dict = piexif.load(im.info['exif'])
exif_dict['Exif'][piexif.ExifIFD.PixelXDimension] = resized_width
exif_dict['Exif'][piexif.ExifIFD.PixelYDimension] = resized_height
im.save(resized_image_path, driver, exif=piexif.dump(exif_dict), quality=100)
else:
im.save(resized_image_path, driver, quality=100)
im.close()
print("{} ({}x{}) --> {} ({}x{})".format(image_path, width, height, resized_image_path, resized_width, resized_height))
except (IOError, ValueError) as e:
print("Error: Cannot resize {}: {}.".format(image_path, str(e)))
nonloc.errors += 1
def resize_gcp(gcp_path, out_path, resize_to, out_path_is_file=False):
"""
:param gcp_path: path to the GCP
:param out_path: path to the output directory or file
:param resize_to: percentage ("perc%") or pixels
"""
try:
if out_path_is_file:
resized_gcp_path = out_path
else:
resized_gcp_path = os.path.join(out_path, os.path.basename(gcp_path))
if resize_to.endswith("%"):
ratio = float(resize_to[:-1]) / 100.0
else:
ratio = resize_to
gcp = GCPFile(gcp_path)
if gcp.entries_count() > 0:
gcp.make_resized_copy(resized_gcp_path, ratio)
else:
raise ValueError("No GCP entries")
print("{} --> {}".format(gcp_path, resized_gcp_path))
except (IOError, ValueError) as e:
print("Error: Cannot resize {}: {}.".format(gcp_path, str(e)))
nonloc.errors += 1
if not args.amount.endswith("%"):
args.amount = float(args.amount)
if args.amount <= 0:
die("Invalid amount")
else:
try:
if float(args.amount[:-1]) <= 0:
die("Invalid amount")
except:
die("Invalid amount")
files = []
gcps = []
if os.path.isdir(args.input):
for ext in ["JPG", "JPEG", "PNG", "TIFF", "TIF"]:
files += glob.glob("{}/*.{}".format(args.input, ext))
files += glob.glob("{}/*.{}".format(args.input, ext.lower()))
gcps = glob.glob("{}/*.txt".format(args.input))
elif os.path.exists(args.input):
_, ext = os.path.splitext(args.input)
if ext.lower() == ".txt":
gcps = [args.input]
else:
files = [args.input]
else:
die("{} does not exist".format(args.input))
create_dir = len(files) > 1 or args.output.endswith("/") or len(gcps) > 1
if create_dir and os.path.isdir(args.output):
if not args.force:
die("{} exists, pass --force to overwrite results")
else:
shutil.rmtree(args.output)
elif not create_dir and os.path.isfile(args.output):
if not args.force:
die("{} exists, pass --force to overwrite results")
else:
os.remove(args.output)
if create_dir:
os.makedirs(args.output)
pool = ThreadPool(processes=multiprocessing.cpu_count())
def resize(file):
_, ext = os.path.splitext(file)
if ext.lower() == ".txt":
return resize_gcp(file, args.output, args.amount, not create_dir)
else:
return resize_image(file, args.output, args.amount, not create_dir)
pool.map(resize, files + gcps)
print("Process completed, {} errors.".format(nonloc.errors))

Wyświetl plik

@ -51,6 +51,25 @@ class GCPFile:
def exists(self):
return bool(self.gcp_path and os.path.exists(self.gcp_path))
def make_resized_copy(self, gcp_file_output, ratio):
"""
Creates a new resized GCP file from an existing GCP file. If one already exists, it will be removed.
:param gcp_file_output output path of new GCP file
:param ratio scale GCP coordinates by this value
:return path to new GCP file
"""
output = [self.raw_srs]
for entry in self.iter_entries():
entry.px *= ratio
entry.py *= ratio
output.append(str(entry))
with open(gcp_file_output, 'w') as f:
f.write('\n'.join(output) + '\n')
return gcp_file_output
def wgs84_utm_zone(self):
"""
Finds the UTM zone where the first point of the GCP falls into