0

I'm writing a program that iterates over a directory of satellite images, crops each image to have a square aspect ratio (1:1), and then saves the cropped image in a different directory created at the beginning of the program. I'm able to crop each image successfully, but the cropped image is being saved to its original directory instead of the one created at the start of the program.

For example, the file path leading up to, but not including, the directory containing imagery is C:\Users\nickm\Documents\Projects\Platform\Imagery, while the directory containing the satellite imagery is dir (a subdirectory of Imagery). After each image is cropped, I want to save it to the directory created at the start of the program (e.g. 10-22-18 cropped, which will also be a subdirectory of Imagery). Instead, it's being saved in dir, overwriting the original image.

Here's my code:

# image.py

import datetime
import os
from PIL import Image

def make_new_dir(abs_path):
    '''Creates the directory where our cropped imagery will be saved and
    returns its absolute file path.
    '''

    date_obj = datetime.datetime.now()
    date = date_obj.strftime('%x').replace('/', '-')

    new_path = abs_path + '/' + date + ' cropped'
    os.mkdir(new_path)

    return new_path

def get_crop_area(image):
    '''Crops each image to have a square aspect ratio (1:1) using the 
    image's size. 
    '''

    image_width, image_height = image.size

    diff = max(image_width, image_height) - min(image_width, image_height)

    if image_width > image_height:
        return [diff / 2, 0, image_width - diff / 2, image_height]
    else:
        return [0, diff / 2, image_width, image_height - diff / 2]

def crop_images(abs_path, image_dir, new_dir):
    '''Iterates over the directory containing the satellite images
    (abs_path + image_dir), cropping each image and saving it to our 
    new directory (the value returned from our make_new_dir function). 
    '''

    new_dir = os.path.abspath(new_dir)

    image_dir = os.path.join(abs_path, image_dir)
    images = os.listdir(image_dir)

    for image in images:

        image_path = os.path.join(image_dir, image)
        image = Image.open(image_path)

        crop_area = get_crop_area(image)
        cropped_image = image.crop(crop_area)

        cropped_image_path = os.path.join(new_dir, image.filename)
        cropped_image.save(cropped_image_path, 'JPEG')

The program is being run with run.py. abs_path and image_dir are being provided by the user at the command line and used as arguments in our make_new_dir and crop_images functions. This is what it looks like when I start my script from the command line:

C:\Users\nickm\Documents\Projects\Code\image>python run.py C:\Users\nickm\Documents\Projects\Platform\Imagery dir

Note that the absolute file path and the directory containing the images are two different command line arguments.

Here's my run.py script:

# run.py 

import sys
from image import make_new_dir, get_crop_area, crop_images


if __name__ == '__main__':
    filename, abs_path, image_dir = sys.argv

    new_dir = make_new_dir(abs_path)

    crop_images(abs_path, image_dir, new_dir)

This is the first program I've created that isn't just a basic coding exercise, so I'm wondering if I'm incorrectly implementing os.path.join. I've looked here and here for clarification, but neither employs the os module, which I'm pretty sure is where I'm encountering my issue.

Thanks in advance for any help provided.

  • Hi @NicholasMaloof does image.filename returns the absolute path? – Dani Mesejo Oct 22 '18 at 21:30
  • `image.filename` returns the name of the file. I'm appending it to `new_dir` to create the file path to the newly created directory. –  Oct 22 '18 at 21:32
  • Yes, but the problem is that if image.filename is an absolute path to your image os.path.join is going to return that path and that may be the reason why the images are being written to the same dir – Dani Mesejo Oct 22 '18 at 21:39
  • I see what you're saying, and you're right. `image.filename` returns the absolute path to the image. I'll investigate how to get just the filename and answer my own question unless someone beats me to it. I'm wondering why it's only returning the absolute path to the image and ignoring the absolute path to `new_dir`. I assumed if I wasn't joining them properly then it would return an error message. –  Oct 22 '18 at 21:49

1 Answers1

0

If image.filename returns the full image path, you can get only the filename by doing this:

image_filename = os.path.basename(image.filename)