Использование только встроенных модулей

Python делает вашу жизнь проще. Для самых разных задач, от создания очень сложного конвейера машинного обучения до организации файлов на вашем компьютере, существует практичное решение Python.

Поэтому я хотел бы назвать Python «языком для всех».

Возвращаясь к тому, как Python помог мне на этот раз, у меня есть список папок, содержащих изображения различных объектов.

Есть более 100 папок, и в каждой из них разное количество изображений. Что мне нужно сделать, так это разделить изображения для каждого объекта на папки обучения (75%) и проверки (25%).

Новая структура будет выглядеть следующим образом:

В качестве первого шага я создаю папки для обучения и проверки. Затем я скопировал все подпапки (например, аккордеон, самолеты и т. д.) в обе эти папки.

Шаги, чтобы сделать это

Задача — удалить 25% изображений из папок поезда и 75% изображений из папок валидации. Важная часть — не удалять одинаковые, чтобы изображения в папках поезда и валидации были разными.

Не очень дружелюбный и утомительный способ — вручную удалять изображения из этих папок. Это определенно исключено. Я уверен, что есть несколько различных практических способов выполнить эту задачу, но мы будем использовать Python.

Мы можем разделить задачу на эти 3 шага:

  • Получить путь к файлам изображений
  • Определите те, которые будут удалены
  • Удалить их

Начнем с первого шага.

Пути к файлам

Мы будем использовать модуль os Python для обработки задач, связанных с путями. Функция listdir возвращает список всех файлов в папке по заданному пути. Указываем путь к папке train и получаем список всех подпапок в ней.

import os
train_base_path = "Data/train/"
train_object_list = os.listdir(train_base_path)
print(train_object_list[:5]) # check the first 5
# output
['gerenuk', 'hawksbill', 'headphone', 'ant', 'butterfly']

Чтобы получить доступ к изображениям внутри этих подпапок, нам нужно создать путь к каждой подпапке, что можно сделать с помощью метода соединения. Сделаем это для первой папки в списке объектов поезда.

folder_path = os.path.join(train_base_path, train_object_list[0])
print(folder_path)
# output
Data/train/gerenuk

Следующим шагом является доступ к изображениям в этой папке, что можно сделать с помощью функции listdir.

image_list = os.listdir(folder_path)

Определяем изображения, которые нужно удалить

Список изображений, созданный на предыдущем шаге, содержит имена всех изображений в указанной папке.

image_list[:5]
# output
['image_0019.jpg',
 'image_0025.jpg',
 'image_0024.jpg',
 'image_0018.jpg',
 'image_0020.jpg']

Следующим шагом является определение того, какие изображения будут удалены из папок поезда и проверки. Существуют разные способы обработки этого шага в зависимости от имен файлов.

Все файлы изображений в нашем случае названы четырехзначным числом, начинающимся с 0001, но они не отсортированы. Мы можем решить эту задачу, выполнив следующие шаги:

  • Найдите количество изображений, используя функцию len Python.
# find the number of images
number_of_images = len(image_list)
  • Рассчитайте количество изображений, которые будут использоваться в папке поезда, умножив общее количество изображений на 0,75 и преобразовав его в целое число. Мы можем использовать функцию int, но она обрезает числа с плавающей запятой (т. е. от 24,8 до 24). Если вы хотите округлить числа с плавающей запятой (например, от 24,8 до 25), вы можете использовать функцию ceil в математической библиотеке.
# number of images in train
number_of_images_train = int(number_of_images * 0.75)
# to round up
import math
number_of_images_train = math.ceil(number_of_images * 0.75)
  • Сортируйте имена изображений в списке изображений, используя встроенную функцию сортировки.
image_list.sort()
  • Определите изображения, которые нужно удалить из папки поезда, используя количество изображений в поезде, чтобы разрезать список изображений.
remove_from_train = image_list[number_of_images_train:]

Если количество изображений в поезде равно 20, список удаления из поезда содержит элементы после первых 20 элементов в списке изображений. Таким образом, первые 20 элементов будут в папке поезда. Мы также можем использовать это значение для удаления изображений из папки проверки.

Удалить изображения из папок обучения и проверки

Мы определили, что изображения должны быть удалены как из папок поезда, так и из папок проверки. Чтобы их удалить, нам нужно сначала построить путь к изображению. Затем образ можно удалить с помощью функции удаления модуля os.

Для каждого имени изображения в списке удаления из поезда путь к файлу изображения может быть создан следующим образом:

for image in remove_from_train:
            
            file_path_to_remove = os.path.join(
                train_base_path, 
                train_object_list[0], 
                image
            )

Вот пример пути к файлу изображения:

'Data/train/metronome/image_0024.jpg'

Последний шаг — удалить образ по этому пути:

os.remove(file_path_to_remove)

Собираем это вместе

Все эти шаги будут выполнены для каждой подпапки как в папках обучения, так и в папках проверки. Таким образом, нам нужно поместить их в цикл.

train_base_path = "Data/train/"
validation_base_path = "Data/validation/"
train_object_list = os.listdir(train_base_path)
for subfolder in train_object_list:
    
    if subfolder != ".DS_Store":
        print(subfolder)
        subfolder_path = os.path.join(train_base_path, subfolder)
        image_list = os.listdir(subfolder_path)
        image_list.sort()
        number_of_images = len(image_list)
        number_of_images_train = int(number_of_images * 0.75)
        remove_from_train = image_list[number_of_images_train:]
        remove_from_validation = image_list[:number_of_images_train]
        
        # remove from train
        for image in remove_from_train:
            
            file_path_to_remove = os.path.join(
                train_base_path, 
                subfolder, 
                image
            )
            os.remove(file_path_to_remove)
            
        # remove from validation
        for image in remove_from_validation:
            
            file_path_to_remove = os.path.join(
                validation_base_path, 
                subfolder, 
                image
            )
            os.remove(file_path_to_remove)

Я поставил условие if для невидимого имени папки «.DS_Store». Я не мог найти его, даже если я проверил скрытые файлы. Дайте мне знать, если у вас есть какие-либо идеи, как эта ситуация может быть решена.

Давайте проверим количество изображений в папках поезда и проверки для первых 5 объектов:

for subfolder in train_object_list[:5]:
    
    subfolder_path_train = os.path.join(train_base_path, subfolder)
    subfolder_path_validation = os.path.join(validation_base_path,
                                             subfolder)
    
    train_count = len(os.listdir(subfolder_path_train))
    validation_count = len(os.listdir(subfolder_path_validation))
    
    print(subfolder, train_count, validation_count)
# output
gerenuk 25 9
hawksbill 75 25
headphone 31 11
ant 31 11
butterfly 68 23

Похоже, наш скрипт выполнил свою работу точно.

Python очень эффективно автоматизирует повседневные задачи, такие как организация файлов и папок, отправка электронных писем и так далее. Если вы часто выполняете такие задачи, я настоятельно рекомендую дать Python возможность сделать это за вас.

Вы можете стать участником Medium, чтобы разблокировать полный доступ к моим материалам, а также к остальной части Medium. Если вы уже подписались, не забудьте подписаться, если хотите получать электронные письма всякий раз, когда я публикую новую статью.

Спасибо за чтение. Пожалуйста, дайте мне знать, если у вас есть какие-либо отзывы.