简体   繁体   中英

Pixel manipulation with PIL.Image and ctypes

I have a C function that does some pixel manipulation on a raw 2D array of 8 bit RGB values. I get the response in a c_ubyte array. My code looks roughly like this:

from ctypes import cdll, CDLL, Structure, byref, c_utype, c_uint

# get a reference to the C shared library
cdll.loadLibrary(path_to_my_c_lib)
myclib = CDLL(path_to_my_c_lib)

# define the ctypes version of the C image that would look something like:
#     struct img {
#         unsigned char data[MAX_IMAGE_SIZE];
#         unsigned int width;
#         unsigned int height;
#     }
class Img(Structure): _fiels_ = [
    ('data', c_ubyte * MAX_IMAGE_SIZE),
    ('width', c_uint),
    ('height', c_uint),
]

# create a blank image, all pixels are black
img = Image()
img.width = WIDTH
img.height = HEIGHT

# call the C function which would look like this:
#     void my_pixel_manipulation_function(struct img *)
# and would now work its magic on the data
myclib.my_pixel_manipulation_function(byref(img))

At this point I'd like to use PIL to write the image to file. I currently use the following code to convert the byte data to image data:

from PIL import Image

s = ''.join([chr(c) for c in img.data[:(img.width*img.height*3)]])
im = Image.fromstring('RGB', (img.width, img.height), s)

# now I can...
im.save(filename)

This works but seems awfully inefficient to me. It takes 125ms for a 592x336 image on a 2.2GHz Core i7. It seems rather silly to iterate over the entire array and do this ridiculous string join when Image could probably grab directly from the array.

I tried looking for ways to cast the c_ubyte array to a string or maybe use Image.frombuffer instead of Image.fromstring but couldn't make this work.

I am not a PIL user, but usually, the frombuffer methods are designed for this kind of job:

Have you tested Image.frombuffer?

http://effbot.org/imagingbook/image.htm

edit:

Apparently sometime the solution is right under our noses:

im = Image.frombuffer('RGB', (img.width, img.height), buff, 'raw', 'RGB', 0, 1)
im.save(filename)

By the way, using the shorthand form of frombuffer :

im = Image.frombuffer('RGB', (img.width, img.height), buff)

generates an upside-down picture. Go figure...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM