Preamble
I'm displaying an image from a Django back-end into a 26 x 26px sized (css) <img> tag.
I can do this two ways:
Resize on the back-end (Pillow) to 26x26 (cropping to keep the aspect ratio)
Send the full size image and let CSS do the sizing
Issue
Using the LANCZOS algorithm for resizing and saving the result as 100% quality Jpg, the displayed image looks so much worse than the one resized by the browser.
Why is that, and is there any way to fix it?
EDIT: Testing on a Retina display
EDIT: Bicubic looks very similar to Lanczos
This article here [1] says that Retina displays (high-DPI displays) are going to try to display 2x more pixels in the same area. Area that is also measured in pixels, the pixels you actually declare in CSS.
So this is where my confusion came from. The solution was to generate the thumbnails twice the size being displayed.
In my experience, PIL/Pillow (hereafter simply “Pillow”) can behave very differently with small images than it does with large ones – not just in its resizing operations but generally – but so you might as well test out all of the methods Pillow offers, e.g.:
# q.v. https://gist.github.com/fish2000/d85befaf289c664b6a9f44d1b56e57da#file-asscat-py-L129-L134
from PIL import Image
# q.v. PIL.Image constants of the same (yet uppercased) names:
interpolation_methods = frozenset({
"box",
"bilinear", "bicubic",
"hamming", "lanczos",
"nearest" })
def interpol(name):
""" Return a PIL/Pillow image interpolation method constant by name """
return getattr(Image, name.upper())
size = (26, 26)
avatar = Image.open(…) # load your source avatar image
methods = (interpol(method) for method in interpolation_methods)
scaled = (avatar.resize(size, resample=method) for method in methods)
# you can save these out for more granular inspection:
previews = list(scaled)
for preview in previews:
preview.show()
… keep in mind that Image.NEAREST can yield surprisingly decent results for small sizes – that, and the fact that Pillow is not in any way Adobe® Photoshop™, and as such can’t really be tasked with replicating results you may have gotten out of same.
But so, w/r/t whether or not to scale using CSS (or any other client-based method): it’s always better to send less bytes over the wire, if possible – but that doesn’t mean it can’t be done. I’m a perfectionist, personally, but if pressed for time or money I am not pedantic about it.
Related
I want to resize my images( to a smaller size) :
How can I resize my images properly without the bad pixels effect for further cnn processing afterward.
Your problems are due to interpolation artifacts. As you can check in the documentation for cv2.resize, by default BILINEAR is used. You should probably go with their suggestion and try using the INTER_AREA version. You may also want to check other options and see which one suits you best.
You need to look at vector images here at Wikipedia if you really want a clear picture in a small size. OpenCV library doesn't provide a function for converting bitmap images to vector images.
I have a django based website in which I have created profiles of people working in the organisation. Since this is a redesign effort, I used the already existing profile pictures. The size of current profile image style is 170x190px. Since the images already exist and are of different sizes, I want to crop them to the size specified above. But how do I decide from which side I have to crop?
Currently, I have applied style of 170by190 to all the images while displaying in profiles, but most of them look distorted as the aspect ratios do not match.
I have tried PIL thumbnail function but it does not fit the need.
Please suggest a solution.
Well, you have to resize pictures, but images ratio create huge impact on final result. As images have some ratio, and you cannot simply resize them to 170px190px without prior adjusting of their ratio, so you have to update( not crop them!) images before resizing them to get best possible output, it can be done in next ways:
Crop them manually to desired ratio (17:19). (take a while if you have plenty of images)
Create script which add padding to that images if image ratio is close to required, all images which ratio is far away from desired mark as 'human cropping required' and work with their ratio later by own (semi-manual, so still may be really time consuming)
Spend some time and write face recognation function, then process images with that function and find faces, then crop them from origin image, but before: add padding to achieve desired radio (17:19) at top and bottom of face. (recommended)
Some links which may be use full for you:
Face Recognition With Python, in Under 25 Lines of Code
facereclib module, they probably are able to help you.
Image Manipulation, The Hitchhiker’s Guide
Good luck !
Use sorl-thumbnail, you don't need to crop every image manually.
I want to write a python code that reads a .jpg picture, alter some of its RBG components and save it again, without changing the picture size.
I tried to load the picture using OpenCV and PyGame, however, when I tried a simple Load/Save code, using three different functions, the resulting images is greater in size than the initial image. This is the code I used.
>>> import cv, pygame # Importing OpenCV & PyGame libraries.
>>> image_opencv = cv.LoadImage('lena.jpg')
>>> image_opencv_matrix = cv.LoadImageM('lena.jpg')
>>> image_pygame = pygame.image.load('lena.jpg')
>>> cv.SaveImage('lena_opencv.jpg', image_opencv)
>>> cv.SaveImage('lena_opencv_matrix.jpg', image_opencv_matrix)
>>> pygame.image.save(image_pygame, 'lena_pygame.jpg')
The original size was 48.3K, and the resulting are 75.5K, 75.5K, 49.9K.
So, I'm not sure I'm missing something that makes the picture original size changes, although I only made a Load/Save, or not?
And is there a better library to use rather than OpenCV or PyGame ?!
JPEG is a lossy image format. When you open and save one, you’re encoding the entire image again. You can adjust the quality settings to approximate the original file size, but you’re going to lose some image quality regardless. There’s no general way to know what the original quality setting was, but if the file size is important, you could guess until you get it close.
The size of a JPEG output depends on 3 things:
The dimensions of the original image. In your case these are the same for all 3 examples.
The color complexity within the image. An image with a lot of detail will be bigger than one that is totally blank.
The quality setting used in the encoder. In your case you used the defaults, which appear to be higher for OpenCV vs. PyGame. A better quality setting will generate a file that's closer to the original (less lossy) but larger.
Because of the lossy nature of JPEG some of this is slightly unpredictable. You can save an image with a particular quality setting, open that new image and save it again at the exact same quality setting, and it will probably be slightly different in size because of the changes introduced when you saved it the first time.
I want to make sure an image that will be saved stays inside the border of my specific dimensions and scales down if any of its dimensions exceed these specific dimensions.
I will be using a gallery for my website using django and the width and height of it is certain, If I use crop while saving an image to keep dimensions under control, it crops a part and as a result doesn't act as I wish.
How can this be achieved ?
You should really look at http://thumbnail.sorl.net/ (especially http://thumbnail.sorl.net/template.html#options), it will solve this and many other problems that you may encounter later.
Using Python's Imaging Library I want to create a PNG file.
I would like it if when printing this image, without any scaling, it would always print at a known and consistent 'size' on the printed page.
Is the resolution encoded in the image?
If so, how do I specify it?
And even if it is, does this have any relevance when it goes to the printer?
As of PIL 1.1.5, there is a way to get the DPI:
im = ... # get image into PIL image instance
dpi = im.info["dpi"] # retrive the DPI
print dpi # (x-res, y-res)
im.info["dpi"] = new dpi # (x-res, y-res)
im.save("PNG") # uses the new DPI
I found a very simple way to get dpi information into the png:
im.save('myfile.png',dpi=[600,600])
Unfortunately I did not find this documented anywhere and had to dig into the PIL source code.
Printers have various resolutions in which they print. If you select a print resolution of 200 DPI for instance (or if it's set as default in the printer driver), then a 200 pixel image should be one inch in size.
Both image print size and resolution are relevant to printing an image of a specific scale and quality. Bear in mind that if the image is then included with a desktop publishing workspace (Word, InDesign) or even a web page, the image is then subject to any specified resolution in the parent document -- this won't necessarily alter the relative scale of the image in the case of desktop publishing programs but will alter image quality.
And yes, all images have a resolution property, which answers half your question - I don't know Python...
Much is going to depend on the software you're using to print. If you're placing the image in a Word document, it will scale according to the DPI, up to the width of your page. If you're putting it on a web page, the DPI will not matter at all.