PIL - сохранение файла в памяти? - PullRequest
0 голосов
/ 29 мая 2020

Я просто хочу открыть файлы изображений в папке и преобразовать их в jpeg, если они еще не jpeg. Единственное, что мне нужно сохранить файл в памяти, а не в файл. Причина в том, что на самом деле я читаю изображения из файла tfrecod (формат файла данных tenorflow), извлекаю из него изображение, проверяю формат файла, если не jpeg, конвертирую в jpeg, а затем записываю обратно в файл tfrecord после правильного декодирования . Поскольку api обнаружения объектов tensorflow, к сожалению, не принимает никаких форматов изображений, кроме jpeg. В любом случае, это только объяснение, почему мне это нужно.

Для этого мне нужно сохранить файл в памяти. Итак, вот мой код:

for counter, filename_with_path in enumerate(filenames):
    e = next(iter(tf.data.TFRecordDataset([filename_with_path])))
    example = tf.train.Example()
    example.ParseFromString(e.numpy())
    parsed = example.features.feature
    image_raw = parsed['image/encoded'].bytes_list.value[0]

    # After this point is important
    stream = BytesIO(image_raw)
    image = Image.open(stream) # Image is pillow image
    stream.close()

    if image.format != 'JPEG':
        tempFile = BytesIO()
        image.convert('RGB')
        image.save(tempFile, format="JPEG")

        newStream = BytesIO(tempFile)
        img = Image.open(newStream)
        newStream.close()

        print(filename, image.format)
        print(filename, img.format)

Когда я запускаю это, я получаю ValueError: I/O operation on closed file. в строке

image.save(tempFile, format="JPEG")

Есть идеи, почему это дает ошибку? Я видел это как предлагаемый способ записи в файл памяти: Как записать изображение PNG в строку с помощью PIL?

1 Ответ

2 голосов
/ 29 мая 2020

Ошибка не в tempFile, а в stream. Вы не должны делать stream.close(), пока не закончите с image. Это ленивый API, поэтому он может более эффективно обрабатывать большие изображения.

for counter, filename_with_path in enumerate(filenames):
    ...

    stream = BytesIO(image_raw)
    image = Image.open(stream) # Image is pillow image
    # remove this line:
    # stream.close()

    if image.format != 'JPEG':
        tempFile = BytesIO()
        image.convert('RGB')
        image.save(tempFile, format="JPEG")

        # this wants bytes, not another BytesIO object, so read it
        newStream = BytesIO(tempFile.read())
        img = Image.open(newStream)
        # same thing, don't close until you are done with img
        # newStream.close()

        print(filename, image.format)
        print(filename, img.format)

Из документа Pillow Image.open docs :

Это ленивая операция; эта функция идентифицирует файл, но файл остается открытым, и фактические данные изображения не считываются из файла, пока вы не попытаетесь обработать данные (или не вызовете метод load ()).

...