Обрезка изображений в методах Keras Data Generator и flow_from_directory () - PullRequest
0 голосов
/ 11 июля 2020

У меня есть прямоугольные angular изображения произвольного размера, которые я хочу обрезать до квадрата по самой короткой стороне, изменить их размер во входную форму и передать в нейронную сеть. Я знаю, что в keras.preprocessing.image.ImageDataGenerator поддерживается множество методов увеличения изображения, но я не видел никаких методов обрезки квадратных изображений.

Существует ли для этого функция keras? Если нет, можно ли использовать внешнюю функцию обрезки и подключить ее где-нибудь между методами ImageDataGenerator и flow_from_directory?.

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

Мой текущий рабочий процесс:

image_shape = (224, 224, 3)

def im_crop(image):
    dim = image.size
    shortest = min(dim[0:2])
    longest = max(dim[0:2])

    lv = np.array(range(0, shortest)) + floor((longest - shortest) / 2)
    if dim[0] == shortest:
        im_cropped = np.asarray(image)[lv, :, :]
    else:
        im_cropped = np.asarray(image)[:, lv, :]

    im_cropped = Image.fromarray(im_cropped)

    return im_cropped

def im_rescale(image, shape):
    im_resized = image.resize((shape[0], shape[1]))
    im_array_resized = np.array(im_resized)
    return im_array_resized

def getFilesLabels(path):
    paths = list()
    files = list()
    labels = list()
    for (dirpath, dirnames, filenames) in os.walk(path):
        paths += [os.path.join(dirpath, file) for file in filenames]
        files += [file for file in filenames]
        labels += [os.path.basename(dirpath) for file in filenames]

    df = pd.DataFrame()
    df['path'] = paths
    df['fname'] = files
    df['label'] = labels

    df = df[~df['fname'].str.contains(".DS_Store")]

    classes = list(set(df['label']))
    num_label = [classes.index(l) for l in df['label']]

    df['num_label'] = num_label
    return df

def get_input(path):
    img = Image.open(path)
    return img

def get_output(path, label_file=None):
    labels = label_file['num_label'][label_file['path'] == path].iloc[0]

    return labels

def val_preprocess_input(image, shape):
    image1 = im_crop(image)
    image2 = im_rescale(image1, shape)
    
    return image2

def train_preprocess_input(image, shape):
    image1 = im_crop(image)
    image2 = im_rescale(image1, shape)

    return image2

def image_generator(df, shape, batch_size=32):
    while True:
        # Select files (paths/indices) for the batch
        batch_paths = np.random.choice(a=df['path'],
                                       size=batch_size)
        batch_input = []
        batch_output = []

        # Read in each input, perform preprocessing and get labels
        for input_path in batch_paths:
            input = get_input(input_path)
            output = get_output(input_path, label_file=df)

            input = train_preprocess_input(image=input, shape=shape)
            batch_input += [input]
            batch_output += [output]
        # Return a tuple of (input, output) to feed the network
        batch_x = np.array(batch_input)
        batch_y = np.array(batch_output)

        yield (batch_x, batch_y)


train_set = getFilesLabels(os.path.join(output_path, "Images/Network Input/train"))
val_set = getFilesLabels(os.path.join(output_path, "Images/Network Input/val"))

train_generator = image_generator(train_set, image_shape)
val_generator = image_generator(val_set, image_shape)

# Generators are then fed to keras.model instance
...