Search code examples
pythonopenimageio

Resize image using Python OpenImageIO maintain aspect ratio


I'm trying to resize an image after doing some additional processing using OpenImageIO and python. However it appears this process not is as easy as PIL. In PIL i can supply a new resolution for example 512 x 512 and it will resize my image regardless of it's current pixel aspect and resize it to fit it's maximum length so it fits inside a 512x512 box. How can i do this using OpenImageIO?

Currently this will just stretch the image to fit withint 512x512.

So images that favor width should fit based on the width value: enter image description here

Whereas images that favor height should fit based on the height value: enter image description here

buf = oiio.ImageBuf(file)
data = buf.spec()
print data.width
print data.height
resized = oiio.ImageBuf(oiio.ImageSpec (512, 512, 3, oiio.FLOAT))
oiio.ImageBufAlgo.resize(resized, buf, roi=oiio.ROI.All, nthreads=4)
resized.write(output)

Solution

  • For simplicity, let's assume that the image origin is (0,0) (i.e., it's not a "crop" or "overscan" image). We can think about images that are wider than they are long ("landscape"), or longer than wide ("portrait").

    I think you want something like the following, which uses the goal width for landscape and the goal height for portrait, and recomputes the proper size in the other direction:

    goal_width = ...
    goal_height = ...
    
    buf = oiio.ImageBuf(file)
    spec = buf.spec()
    w = spec.width
    h = spec.height
    aspect = float(w) / float(h)
    if aspect >= 1.0 :
        # source image is landscape (or square)
        goal_height = int(h * goal_height / w)
    else :
        # source image is portrait
        goal_width = (w * goal_width / h)
    
    resized = oiio.ImageBuf(oiio.ImageSpec (goal_width, goal_height, spec.nchannels, spec.format))
    oiio.ImageBufAlgo.resize(resized, buf)
    resized.write(output)
    

    That's off the top of my head, you should test it and adjust if I've made mistakes. But that's the gist.

    Aside: note that when I create the resized buf, I used the number of channels and data format of the original file, which is a bit more robust than hard-coding it to 3 chans float as you did in the original.