Search code examples
pythonimage-processingvips

Shrinking image by pixel-binning using VIPS


I need to shrink some images by factor of 2 or 3 using VIPS. This has to be achieved through simple pixel binning (pixel averaging), with no additional smoothing or interpolation.

VIPS offers several functions at different levels of abstraction for resizing images (resize, shrink, reduce, affine, etc.). It also offers different interpolation methods with these functions.

I wonder what combination of functions and methods leads to simple pixel binning in VIPS. A rudimentary example would be very helpful.


Solution

  • You need shrink. With integer arguments, it does simple block averaging of pixels.

    im = Vips.Image.new_from_file("somefile.jpg")
    im = im.shrink(2, 2)
    im.write_to_file("someotherfile.tif")
    

    The pixel format stays the same, so for a uchar image, you'll get uchar averages, rounded to the nearest value. Cast to float, shrink, and round yourself if you want something different.

    libvips treats image resolution (the number of pixels per inch, or whatever the unit is) as a bit of metadata which is carried around for you by the system and used in load and save operations, but not updated by vips itself. This is because image resolution is usually more complicated than a simple measure of pixels per distance and the application has a better chance of doing the right thing than the library.

    If you want to read out the resolution, use .xres and .yres. They are always in pixels-per-millimeter and get converted to and from the appropriate unit on load and save.

    print "im.xres =", im.xres, "ppm"
    

    libvips images are immutable, so you can't just assign to xres/yres, you need to make a new image with those values changed. To set a new value, use .copy(). Behind the scenes, .copy() just copies pointers, so it's very fast. The example above could be:

    im = Vips.Image.new_from_file("somefile.jpg")
    im = im.shrink(2, 2)
    im = im.copy(xres = im.xres / 2.0, yres = im.yres / 2.0)
    im.write_to_file("someotherfile.tif")
    

    I've added a note to the introduction to that section of the manual explaining what shrink and reduce do.