Python PIL: best scaling method that preserves lines
I have a 2D drawing with a black background and white lines (exported from Autocad) and I want to create a thumbnail preserving lines, using Python PIL library.
But what I obtain using the 'thumbnail' method is just a black picture scattered with white dots.
Note that if I put the image into an IMG tag with fixed width, I obtain exactly what I want (but the image is entirely loaded).
After your comments, here is my sample code:
from PIL imp开发者_高级运维ort Image
fn = 'filename.gif'
im = Image(fn)
im.convert('RGB')
im.thumbnail((300, 300), Image.ANTIALIAS)
im.save('newfilename.png', 'PNG')
How can I do?
The default resizing method used by thumbnail
is NEAREST, which is a really bad choice. If you're resizing to 1/5 of the original size for example, it will output one pixel and throw out the next 4 - a one-pixel wide line has only a 1 out of 5 chance of showing up at all in the result!
The surprising thing is that BILINEAR and BICUBIC aren't much better. They take a formula and apply it to the 2 or 3 closest pixels to the source point, but there's still lots of pixels they don't look at, and the formula will deemphasize the line anyway.
The best choice is ANTIALIAS, which appears to take all of the original image into consideration without throwing away any pixels. The lines will become dimmer but they won't disappear entirely; you can do an extra step to improve the contrast if necessary.
Note that all of these methods will fall back to NEAREST if you're working with a paletted image, i.e. im.mode == 'P'
. You must always convert to 'RGB'.
from PIL import Image
im = Image.open(fn)
im = im.convert('RGB')
im.thumbnail(size, Image.ANTIALIAS)
Here's an example taken from the electronics.stackexchange site https://electronics.stackexchange.com/questions/5412/easiest-and-best-poe-ethernet-chip-micro-design-for-diy-interface-with-custom-ard/5418#5418
Using the default NEAREST algorithm, which I assume is similar to the results you had:
Using the ANTIALIAS algorithm:
By default, im.resize
uses the NEAREST
filter, which is going to do what you're seeing -- lose information unless it happens to fall on an appropriately moduloed pixel.
Instead call
im.resize(size, Image.BILINEAR)
This should preserve your lines. If not, try Image.BICUBIC
or Image.ANTIALIAS
. Any of those should work better than NEAREST
.
精彩评论