问题
I wrote this code to switch the red and blue values in the RGB array from a given image:
from PIL import Image
import numpy as np
image = Image.open("image.jpg")
RGBarr = np.asarray(image)
newRGB = np.full_like(RGBarr, 1)
red = RGBarr[..., 0]
green = RGBarr[...,1]
blue = RGBarr[..., 2]
newRGB[..., 0] = blue
newRGB[..., 1] = green
newRGB[..., 2] = red
inv_image = Image.fromarray(newRGB, 'RGB')
inv_image.save('inv_image.png')
inv_image.show()
I tried it with multiple images, and it works almost every time. However, in some cases I get the following error:
raise ValueError("not enough image data")
ValueError: not enough image data
That can be fixed if I do not specify the mode in Image.fromarray(obj, mode)
, but even doing that I am not sure if the result I obtain is the "correct" one.
Is there a way to determine what mode should be used for a certain image?
I hope this is not a dumb question, but I am sort of new in this image processing business.
回答1:
The error occurs, when you try to read images which are not RGB like grayscale images or RGBA images. To keep the rest of your code valid, the easiest way would be to enforce RGB input by using:
image = Image.open("image.jpg").convert('RGB')
Then, possible grayscale or RGBA images are converted to RGB, and can be processed as regular RGB images.
As you found out yourself,
inv_image = Image.fromarray(newRGB)
also works, but the processing from the rest of your code then isn't correct anymore (no proper slicing of the desired dimensions/axes). That would require further work on your code to also respect grayscale or RGBA images.
Hope that helps!
EDIT: To incorporate furas' idea to get rid of NumPy, here's a PIL only way of swapping the channels. Notice: You still need the enforced RGB input.
from PIL import Image
image = Image.open('image.jpg').convert('RGB')
r, g, b = image.split()
inv_image = Image.merge('RGB', (b, g, r))
inv_image.save('inv_image.png')
inv_image.show()
回答2:
If you want to re-order RGB
channels to BGR
with Numpy, it is much simpler to do this:
BGR = RGB[...,::-1]
which just addresses the last index (i.e. the channels) in reverse. It has the benefit of being O(1) which means it takes the same amount of time regardless of the size of the array. On my Mac, it takes 180ns to do BGR->RGB with 10x10 image and just the same with a 10,000x10,000 image.
In general, you may want some other ordering rather than straight reversal, so if you want BGR->BRG, you can do:
BRG = BGR[...,(0,2,1)]
Or, if you want to make a 3-channel greyscale image by repeating the Green channel three times (because the green is usually the least noisy - see Wikipedia Bayer array article), you can simply do this:
RGBgrey = BGR[...,(1,1,1)]
If you want to get rid of Numpy, you can do it straight in PIL/Pillow using a matrix multiplication:
# Open image
im = Image.open('image.jpg')
# Define matrix to re-order RGB->BGR
Matrix = ( 0, 0, 1, 0,
0, 1, 0, 0,
1, 0, 0, 0)
# BGR -> RGB
BGR = im.convert("RGB", Matrix)
You can understand the matrix like this:
newR = 0*oldR + 0*oldG + 1*oldB + 0 offset
newG = 0*oldR + 1*oldG + 0*oldB + 0 offset
newB = 1*oldR + 0*oldG + 0*oldB + 0 offset
Input
Result
来源:https://stackoverflow.com/questions/58872621/when-converting-an-image-into-an-array-and-viceversa-are-there-extra-considerat