Загрузка изображений в Dask Dataframe - PullRequest
1 голос
/ 16 июня 2019

У меня есть dask dataframe, который содержит пути к изображениям в столбце (называемый img_paths). На следующих шагах я хочу загрузить изображения, используя эти пути к изображениям, в другой столбец (называемый img_loaded), а затем применить некоторые функции предварительной обработки.

Тем не менее, во время процесса загрузки (или чтения изображения) я всегда получаю разные результаты, включая одноразовую задержку переноса функции imread, другую правильную загрузку изображения (я вижу массивы) и остальное время: FileNotFoundError.

В дополнение к следующим примерам я также использовал функцию map_partitions, но я также получил аналогичные выходы, за исключением того, что у меня нет массивов. В конце я хочу использовать функцию map_partitions, а не функцию apply.

Ниже приведен мой код и описания проблем:

import pandas as pd
import dask
import dask.dataframe as dd
from skimage.io import imread

imgs = ['https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a'] * 42

# create a pandas dataframe using image paths
df = pd.DataFrame({"img_paths": imgs})

# convert it into dask dataframe
ddf = dd.from_pandas(df, npartitions=2)

# convert imread function as delayed
delayed_imread = dask.delayed(imread, pure=True)

Первая попытка: использование лямбда-функции и применение отложенного imread к каждой ячейке

ddf["img_loaded"] = ddf.images.apply(lambda x: delayed_imread(x))
ddf.compute()

Здесь я получаю обертку отложенной функции imread при использовании метода compute(). Я не понимаю почему? Следующий вывод:

enter image description here

Вторая попытка: без использования лямбда-функции

ddf["img_loaded"] = ddf.images.apply(delayed_imread)
ddf.compute()

Это сработало! По крайней мере, я могу видеть загруженные изображения в виде массивов. Но я действительно не понимаю, почему? почему это отличается от первого решения (т. е. с использованием лямбда-функции) Ниже приводится вывод:

enter image description here

Третья попытка: с / без использования лямбда-функции и без использования задержки imread.

ddf["load"] = ddf.images.apply(imread) # or, lambda x: imread(x)
ddf.compute()

Здесь, опять же, просто для экспериментов, я не использовал отложенную функцию imread, а просто функцию skimage.io.imread. И я пробовал как с использованием и без лямбда-функции. В каждый раз я получал FileNotFoundError. Я не получил это. Почему он не может найти путь к изображению (хотя они верны) при использовании функции отложенного считывания?

В дополнение к ответу Рональда, как использовать функцию map_partitions:

ddf["img_loaded"] = ddf.map_partitions(lambda df: df.images.apply(lambda x: imread(x)), meta=("images", np.uint8)).compute()
ddf.compute()

1 Ответ

1 голос
/ 17 июня 2019

Решение

import pandas as pd
import dask
import dask.dataframe as dd
import numpy as np
from skimage.io import imread

imgs = ['https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a'] * 4

# create a pandas dataframe using image paths
df = pd.DataFrame({"img_paths": imgs})

# convert it into dask dataframe
ddf = dd.from_pandas(df, npartitions=2)

# convert imread function as delayed
delayed_imread = dask.delayed(imread, pure=True)

# give dask information about the function output type
ddf['img_paths'].apply(imread, meta=('img_loaded', np.uint8)).compute()

# OR turn it into dask.dealayed, which infers output type `object`
ddf['img_paths'].apply(delayed_imread).compute()

Объяснение

Если вы попытаетесь применить функцию print, без вычислений вы увидите причину FileNotFoundError кода: ddf.images.apply(imread).compute()

ddf['img_paths'].apply(print)

Выход:

> foo
> foo

Когда вы добавляете функцию apply к графику, Dask запускает через нее строку foo, чтобы определить тип вывода => imreadпытался открыть файл с именем foo.

. Чтобы лучше понять, я советую вам попробовать:

ddf.apply(print, axis=1)

и попытаться предсказать, что будет напечатано.

Задержанные ячейки после .compute()

Причина в том, что apply ожидает ссылку на функцию, которая затем вызывается.Создавая лямбда-функцию, вызывающую отложенную функцию, вы в основном удваиваете свою функцию.

...