Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(Py)Vips vs Pillow upscaling image quality

Resizing an image to 200% yields a difference in quality between Pillow and pyvips.

While Pillow is very accurate in the reproduction, vips exaggerates noise and contrast.

I need to use vips for very large images, but the quality is unsatisfactory. Any idea how to get better upscaling from vips? (From the docs I gathered that upscaling isn't really that important for vips and most thought has gone into downscaling).

example:

from PIL import Image
import pyvips
import numpy as np

#Vips
img = pyvips.Image.new_from_file("mypic.jpg", access='sequential')
out = img.resize(2, kernel = "linear")
out.write_to_file("mypic_vips_resized.tif")

#Pillow
img = np.array(Image.open("mypic.jpg"))
h, w = img.shape[:2]
out = Image.fromarray(img,mode="RGB")
out = out.resize((w*2,h*2), Image.BILINEAR)
out.save("mypic_PIL_resized.tif", format='TIFF', compression='None')

Original:
original
Pillow:
Pillow
Vips:
Vips

Abstract examples (10*10 Pixels)

Original:
Original
Pillow Bilinear:
Pillow Bilinear
Vips linear:
Vips linear

like image 284
Horst Avatar asked Oct 29 '22 01:10

Horst


1 Answers

It looks like Pillow is upsizing with a triangle filter for LINEAR, whereas for upsize libvips is doing simple interpolation. libvips uses a triangle filter for downsize.

If you imagine pixels:

A 
B 
C 

Then Pillow is calculating the new pixel between A and B, the pixel at B's position, and the new pixel between B and C as:

(A + B) / 2
(A + B) / 4 + B / 2 + (B + C) / 4
(B + C) / 2

Whereas libvips is calculating:

(A + B) / 2
B
(B + C) / 2

You can get the effect of a triangle filter by doing a very mild blur first. If I change your program to be:

img = pyvips.Image.new_from_file('mypic.png', access='sequential')
img = img.gaussblur(0.45, precision='float', min_ampl=0.01).cast('uchar')
out = img.resize(2, kernel='linear')
out.write_to_file('mypic_vips_resized_blur.png')

ie. do a small radius, high-precision gaussblur first, I get:

enter image description here

Where left-to-right the images are 1) a simple x2 pixel double, 2) Pillow LINEAR, 3) libvips linear, and 4) libvips gaussblur + linear. You'll probably need to click on the image or your browser will shrink it and blur it.

2) and 4) seem reasonably close to my (not great) eyes. 3) seems arguably more truthful to the original, since the ringing and noise present in the original have not been smoothed out.

like image 74
jcupitt Avatar answered Nov 15 '22 07:11

jcupitt