Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

About using Image.ANTIALIAS with resize (downscaling) #6200

Closed
mitchellwiebe opened this issue Apr 11, 2022 · 5 comments
Closed

About using Image.ANTIALIAS with resize (downscaling) #6200

mitchellwiebe opened this issue Apr 11, 2022 · 5 comments
Labels

Comments

@mitchellwiebe
Copy link

Hi there,

I've been trying to understand how images are resized (specifically downscaled) when using Image.ANTIALIAS. I understand that a Lanczos kernel is involved, but not exactly sure how. For example, if an image is being downscaled to half of its original size, is the process something like: 1.) Lanczos low-pass filter applied, 2.) Retain every second pixel? Or is something more/less technical going on here?

Thanks for your time,
Mitch

@hugovk
Copy link
Member

hugovk commented Apr 11, 2022

Yes, Image.ANTIALIAS and Image.LANCZOS are aliases (and by the way both are deprecated in favour of Image.Resampling.LANCZOS).

Here's a blogpost about the different methods in Pillow:

https://uploadcare.com/blog/the-fastest-image-resize/

@radarhere
Copy link
Member

@mitchellwiebe did that answer your question, or no?

@mitchellwiebe
Copy link
Author

It did help with the general concept. I suppose what I am really looking for is a toy example of what happens to the pixels of a sample image to obtain the downsized image in this way. I see lots of examples online of how images are upscaled and values must be interpolated (to determine pixel values between the original image pixels); however, it is difficult to visualize how this works for the downscaling case - as the final image has fewer pixels than the original.

I hope my message makes sense.

@radarhere
Copy link
Member

The previously linked article does have a section talking about downscaling - https://uploadcare.com/blog/the-fastest-image-resize/#convolution-based-resampling.

There are two passes over the image - horizontal, and then vertical.

/* two-pass resize, horizontal pass */

The filter chosen is used to calculate the coefficients for each pass. Our lanczos function is truncated to between -3 and 3 (https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel, where 'a' is 3).

As far as visualising, I suggest looking at the Lanczos graph from the article,
image
and then consider this simple example - if I take a 1 dimensional image with (1, 2, 3, 4) and downscale it to a single pixel, we apply the coefficients that the Lanczos function generates ((0.220116, 0.279884, 0.279884, 0.220116)), then 0.220116 * 1 + 0.279884 * 2 + 0.279884 * 3 + 0.220116 * 4 = 2.5, which can be rounded to 3, the value that Pillow generates from the following code.

from PIL import Image
im = Image.new("L", (4, 1))
px = im.load()
px[0, 0] = 1
px[1, 0] = 2
px[2, 0] = 3
px[3, 0] = 4

im = im.resize((1, 1), Image.Resampling.LANCZOS)
print(im.getpixel((0, 0)))

So in words, the Lanczos curve is applied to the pixels, considering the values of closer pixels more heavily, and the values of more distant pixels less heavily.

@mitchellwiebe
Copy link
Author

Hi radarhere and hugovk,

I may have been overthinking things but this has helped to clarify my confusion. Thank you very much for your help, it is greatly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants