PIL cannot write mode F to jpeg
Asked Answered
G

7

85

I am taking a jpg image and using numpy's fft2 to create/save a new image. However it throws this error

"IOError: cannot write mode F as JPEG" 

Is there an issue with CMYK and JPEG files in PIL???

p = Image.open('kibera.jpg')
bw_p = p.convert('L')
array_p = numpy.asarray(bw_p)
fft_p = abs(numpy.fft.rfft2(array_p))
new_p = Image.fromarray(fft_p)
new_p.save('kibera0.jpg')
new_p.histogram()
Goat answered 23/5, 2013 at 17:52 Comment(0)
S
83

Try convert the image to RGB:

...
new_p = Image.fromarray(fft_p)
if new_p.mode != 'RGB':
    new_p = new_p.convert('RGB')
...
Sadoc answered 18/9, 2013 at 18:13 Comment(3)
What if an image is in grayscale?Paleface
Bump, what if I want to save as grayscale?Raoul
Just use this. It works just fine with grayscale as well.Askari
S
53

Semente's answer is right for color images For grayscale images you can use below:-

new_p = Image.fromarray(fft_p)
new_p = new_p.convert("L")

If you use new_p = new_p.convert('RGB') for a grayscale image then the image will still have 24 bit depth instead of 8 bit and would occupy thrice the size on hard disk and it wont be a true grayscale image.

Symon answered 18/8, 2018 at 14:28 Comment(1)
More info on convert here: pillow.readthedocs.io/en/stable/reference/…Downpour
M
21

I think it may be that your fft_p array is in float type and the image should have every pixel in the format 0-255 (which is uint8), so maybe you can try doing this before creating the image from array:

fft_p = fft_p.astype(np.uint8)
new_p = Image.fromarray(fft_p)

But be aware that every element in the fft_p array should be in the 0-255 range, so maybe you would need to do some processing to that before to get the desired results, for example if you every element is a float between 0 and 1 you can multiply them by 255.

Mediative answered 1/2, 2020 at 4:54 Comment(2)
This is the true answer because it does not changing the actual value of the numpy array (just the type format).Nellenelli
Very useful hint that it should be uint8. I was trying to preview the mnist grayscale data on jupyter and encountered this issue. The correct code should be like `Image.fromarray((mnist_images[0]*255).astype(np.uint8))Lower
M
3
def save_img(img, path):

    img = Image.fromarray(img)

    img.save(path)

raise OSError(f"cannot write mode {mode} as PNG") from e

OSError: cannot write mode F as PNG

Here the meaning of mode F is the floating point value in the image. So please convert the floating point image to the uint8 image before saving.

image.astype(np.uint8)
Mackenie answered 6/10, 2022 at 7:13 Comment(0)
P
1

If you are working with PyTorch

import torchvision.transforms as T
    
        
transform=T.ToPILImage()
imt=transform(img)
Providential answered 20/10, 2022 at 10:47 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Alkyl
C
1

I had the same issue, but my image was a gray-scale one, consisting of only float numbers between 0 and 1. I was able to save my image with the original data through the following method:

import PIL as pillow, numpy

# Normalize the image with values between 0 and 255
normalized_image = (final_image - numpy.min(final_image)) * (255.0 / (numpy.max(final_image) - numpy.min(final_image)))
normalized_image = normalized_image.astype('uint8')

# Convert the normalized numpy array to an image using Pillow
image = pillow.Image.fromarray(normalized_image)

# Save the final image
image.save('image.png')
Crumhorn answered 10/12, 2023 at 14:26 Comment(0)
I
0

In my case I was getting error while trying to save the image array with floating-point values. I solved the issue by first converting the floating-point to an 8 bit image. I am sharng the code that worked for me.

import numpy as np
import imageio

res_uint8 = (res - res.min()) / (res.max() - res.min())  # Normalize the image to 0-1
res_uint8 = (255 * res_uint8).astype(np.uint8)  # Scale to 0-255 and convert to uint8

imageio.imsave(save_path + name, res_uint8)
Intended answered 9/6 at 12:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.