问题
I've had hard time to read data I received from a USB camera and display it correctly. I succeeded, but I worry that I'm doing something wrong because my solution is hacky.
The usb camera I'm using (ui-1640le) returns a byte array that I want to display.
I used PIL.Image.frombytes("RGB", (imageWidth, imageHeight), image_bytes)
But the image I got was in black and white and repeated itself:
Image result
I tried using the "L"
format. PIL.Image.frombytes("L", (imageWidth, imageHeight), image_bytes)
to see what will happen and I got: this B&W image. Except for being B&W the image looked correct and the function only read third of the data.
So I reverse engineered the data with this code:
# Reorder the bytes structure
x=[]
for i in range(width*height):
x += [img[i],img[i+width*height],img[i+2*width*height]]
image_bytes = bytes(x)
# Create a PIL Image
im = PIL.Image.frombytes("RGB", (imageWidth, imageHeight), image_bytes)
# Not sure why the image is flipped, but this fixes it
im.rotate(-90).transpose(PIL.Image.FLIP_LEFT_RIGHT).show()
After that I finally get the picture as it should be: final image
Does this solution make sense to read camera input, am I doing something wrong? Is there a more straight forward approach I'm missing?
回答1:
Whilst your method of packing the planar-interleaved data into pixel-interleaved data will work, you will almost certainly find the Numpy method is many tens of times faster.
First, I'll synthesise your input data:
import numpy as np
# Height, width and bytes per image channel
h,w = 100,256
bpc = h * w
# Now make the first (red) plane = 255, the second (green) plane = 127 and the final (blue) plane = 0
img = bytes(b"\xff"*bpc) + bytes(b"\x7f"*bpc) + bytes(b"\x00"*bpc)
So, img
should now be a representative 100x256 orange image such as you might acquire. I would then interleave the data and make a PIL Image like this with Numpy:
from PIL import Image
# Make a Numpy array for each channel's pixels
R = np.frombuffer(img, dtype=np.uint8, count=bpc).reshape((h,w))
G = np.frombuffer(img, dtype=np.uint8, count=bpc, offset=bpc).reshape((h,w))
B = np.frombuffer(img, dtype=np.uint8, count=bpc, offset=2*bpc).reshape((h,w))
# Interleave the pixels from RRRRRRGGGGGGBBBBBB to RGBRGBRGBRGBRGB
RGB = np.dstack((R,G,B))
# Make PIL Image from Numpy array
pImage = Image.fromarray(RGB)
That takes 30 microseconds on my machine, versus 7 milliseconds with for
loops, so some 230x faster.
Keywords: Python, Numpy, PIL, image processing, interleave, interleaved, de-interleave, planar, by pixel, by plane, pack, unpack.
来源:https://stackoverflow.com/questions/59745279/how-to-correctly-format-pil-image-frombytes-using-external-usb-camera-data