Why does PIL.Image.rotate() results in loss of quality despite `resample=Image.BICUBIC` - python-imaging-library

Per https://stackoverflow.com/a/17822099/1639359 using resample=PIL.Image.BICUBIC should retain quality through rotation. This question is follow up from my comment on the above answer that it is not working for me.
What version of Python and PIL do we have:
import sys
print(sys.version)
3.7.3 (default, Mar 27 2019, 22:11:17)
[GCC 7.3.0]
import PIL
import PIL.Image
print(PIL.__version__)
print(PIL.Image.__version__)
6.2.1
6.2.1
Open our test image, and save it. Notice the loss of quality; saved file is much smaller than original:
img = PIL.Image.open('test_image.jpg')
holdexif = img.info['exif']
img.save('testsave.jpg',"jpeg",exif=holdexif)
%ls -l 'test_image.jpg'
%ls -l 'testsave.jpg'
-rwxrwxrwx 1 dino dino 1926859 Dec 24 21:28 test_image.jpg*
-rwxrwxrwx 1 dino dino 452343 Dec 27 13:16 testsave.jpg*
Per Determining JPG quality in Python (PIL) setting quality='keep' prevents the loss of quality on save:
img.save('testsave.jpg',"jpeg",exif=holdexif,quality='keep')
%ls -l 'test_image.jpg'
%ls -l 'testsave.jpg'
-rwxrwxrwx 1 dino dino 1926859 Dec 24 21:28 test_image.jpg*
-rwxrwxrwx 1 dino dino 1926911 Dec 27 13:16 testsave.jpg*
If we rotate the image, two things happen:
img.format disappears
quality is reduced significantly (even though we use resample=PIL.Image.BICUBIC)
print(img.format)
JPEG
rotated_img = img.rotate(-90,resample=PIL.Image.BICUBIC,expand=True)
print(img.format)
print(rotated_img.format)
JPEG
None
Saving the rotated file shows the loss of quality:
rotated_img.format="JPEG" # quality='keep' will raise exception if format != 'JPEG'
rotated_img.save('testsave.jpg',"jpeg",exif=holdexif,quality='keep')
%ls -l 'test_image.jpg'
%ls -l 'testsave.jpg'
-rwxrwxrwx 1 dino dino 1926859 Dec 24 21:28 test_image.jpg*
-rwxrwxrwx 1 dino dino 450997 Dec 27 13:16 testsave.jpg*
Questions:
1. What, if anything, am I doing wrong?
2. Why does img.format disappear on rotate? What else is disappearing?
3. And, just as an aside, is there another way to detect the loss of quality (I only know to save the file and see that it is much smaller).
After #MarkRansom 's comments, I would like to add some color to my question: Although I have been coding for many years, I only last week began playing with images. Without a doubt my knowledge of image processing is minimal at best, with significant gaps and misunderstandings about how things work.
That said, from a coding perspective, I would expect that a method on an object would do pretty much only what that method suggests, with no side effects. For example, I would expect rotate() only to rotate the image, and not clear out meta data at the same time. Even if, let's say for efficiency sake, the default behavior for the PIL package is to always drop the meta data, I would hope there would be an option (either global, or on a per-method basis) for something like preserve_metadata=True
Regarding "the only good way to judge quality" being "to look at the images themselves," I can certainly understand that being the case on an absolute basis. However on a relative basis, most notably when comparing the "same" image before and after some processing, it seems to me there could be ways to physically measure, or at least estimate, the difference in quality before and after the processing. (Of course, I don't yet know enough about images to know what the best method of doing that would be; thus part of the reason for my question). It also seems to me (at least from my beginner perspective) that very often people would want to do whatever processing that want to do with little or no loss of quality at the same time. Thanks for your patience and help filling in my knowledge gaps, and with the answers.

In general, any image rotation is going to result in a loss of image quality simply because the output requires an interpolation of the input for pixels that don't map 1:1 from input to output. For rotations of multiples of 90 degrees, it's possible to get a 1:1 mapping and do a lossless rotation. It's not clear if PIL/Pillow is smart enough to do that, but it might. Your example rotates by -90 degrees so you could luck out.
The metadata is being lost because rotate generates a new image, it doesn't modify the existing one. It's not easy to determine which metadata might be relevant for the new image, so the safest course of action is to simply not copy any of it. As you've discovered, it's possible to manually copy anything you think is important. I don't think there's an option to automatically copy anything.
As noted in the comments, using file size as a judge of image quality is a very poor metric. A smaller size is suggestive of poorer quality, but it doesn't have to be so; the whole premise of JPEG compression is that some image degradations simply won't be visible in normal viewing. A visual comparison is the ultimate test. If you must have an automated comparison there are methods to do so, but I don't think any have emerged as the undisputed best way to compare.

You rotated the image, which creates a new generic image. There is no 'keep' in this instance. When saving to JPEG, default quality is 75, high quality is 95.
Need to copy quality, perhaps tables, and metadata to the new image, just as you are doing with the Exif.

Related

Adding Small Assets Increases Standalone Data Folder Size Exponentially

I added 33 mb worth of sprite assets (they are large character illustrations), so I would expect the data folder to increase proportionally. However, the size actually increases by 2 GB (6000% increase!) increasing total data size by over 500% too.
Doesn't make any sense to me. Is there a mistake with my import options? I use mip maps, bilinear/trilinear filters. Truecolor/ vs compressed doesn't change anything.
Additional info: It's like 10 files with 5-8 large sprites each. Another weird thing is that when it's compressed to a zip file the size collapses to 142mb (from like 2.3 GB). Which is weird because that's too big of a difference.
It's also very slow to start.
I believe this is related to how unity handles image compression. The assets live in your project in compressed (jpg/png) form, but they get recompressed (or not) to a form thats fastest to decode on the target platform. Try playing with the compession settings with the asset import settings (available if you highlight your asset in the project window)
There are a few reasons why file sizes can get so big.
As #zambari said, PNG/JPEG are compressed forms, which compress much better than what unity will. Due to that, you have to be careful with your file sizes, since they will be much bigger in-game.
Another issue I had was that my files weren't sized properly. The compression method that I was trying to utilize requires file sizes divisible by 4 (DTX5).
Another big issue was I had large images that I did not need. I used "generate mip-maps" + trilinear filtering, and that once again doubled the file sizes. The best thing you can do is just use image sizes that reflect their use. Relying on Unity to do that for you by using max image size does not guarantee good quality (in fact it looked terrible). This was all in Unity 5

BMP image header - biXPelsPerMeter

I have read a lot about BMP file format structure but I still cannot get what is the real meaning of the fields "biXPelsPermeter" and "biYPelsPermeter". I mean in practical way, how is it used or how it can be utilized. Any example or experience? Thanks a lot
biXPelsPermeter
Specifies the horizontal print resolution, in pixels per meter, of the target device for the bitmap.
biYPelsPermeter
Specifies the vertical print resolution.
Its not very important. You can leave them on 2835 its not going to ruin the image.
(72 DPI × 39.3701 inches per meter yields 2834.6472)
Think of it this way: The image bits within the BMP structure define the shape of the image using that much data (that much information describes the image), but that information must then be translated to a target device using a measuring system to indicate its applied resolution in practical use.
For example, if the BMP is 10,000 pixels wide, and 4,000 pixels high, that explains how much raw detail exists within the image bits. However, that image information must then be applied to some target. It uses the relationship to the dpi and its target to derive the applied resolution.
If it were printed at 1000 dpi then it's only going to give you an image with 10" x 4" but one with extremely high detail to the naked eye (more pixels per square inch). By contrast, if it's printed at only 100 dpi, then you'll get an image that's 100" x 40" with low detail (fewer pixels per square inch), but both of them have the same overall number of bits within. You can actually scale an image without scaling any of its internal image data by merely changing the dpi to non-standard values.
Also, using 72 dpi is a throwback to ancient printing techniques (https://en.wikipedia.org/wiki/Twip) which are not really relevant in moving forward (except to maintain compatibility with standards) as modern hardware devices often use other values for their fundamental relationships to image data. For video screens, for example, Macs use 72 dpi as the default. Windows uses 96 dpi. Others are similar. In theory you can set it to whatever you want, but be warned that not all software honors the internal settings and will instead assume a particular size. This can affect the way images are scaled within the app, even though the actual image data within hasn't changed.

Tesseract Trained data

Am trying to extract data from reciepts and bills using Tessaract , am using tesseract 3.02 version .
am using only english data , Still the output accuracy is about 60%.
Is there any trained data available which i just replace in tessdata folder
This is the image nicky provided as a "typical example file":
Looking at it I'd clearly say: "Forget it, nicky! You cannot train Tesseract to recognize 100% of text from this type of image!"
However, you could train yourself to make better photos with your iPhone 3GS (that's the device which was used for the example pictures) from such type of receipts. Here are a few tips:
Don't use a dark background. Use white instead.
Don't let the receipt paper crumble. Straighten it out.
Don't place the receipt loosely on an uneven underground. Fix it to a flat surface:
Either place it on a white sheet of paper and put a glas platen over it.
Or use some glue and glue it flat on a white sheet of paper without any bend-up edges or corners.
Don't use a low resolution like just 640x480 pixels (as the example picture has). Use a higher one, such as 1280x960 pixels instead.
Don't use standard exposure. Set the camera to use extremely high contrast. You want the letters to be black and the white background to be really white (you don't need the grays in the picture...)
Try to make it so that any character of a 10-12 pt font uses about 24-30 pixels in height (that is, make the image to be about 300 dpi for 100% zoom).
That said, something like the following ImageMagick command will probably increase Tesseract's recognition rate by some degree:
convert \
http://i.stack.imgur.com/q3Ad4.jpg \
-colorspace gray \
-rotate 90 \
-crop 260x540+110+75 +repage \
-scale 166% \
-normalize \
-colors 32 \
out1.png
It produces the following output:
You could even add something like -threshold 30% as the last commandline option to above command to get this:
(You should play a bit with some variations to the 30% value to tweak the result... I don't have the time for this.)
Taking accurate info from a receipt is not impossible with tesseract. You will need to add image filters and some other tools such as OpenCV, NumPy ImageMagick alongside Tesseract. There was a presentation at PyCon 2013 by Franck Chastagnol where he describes how his company did it.
Here is the link:
http://pyvideo.org/video/1702/building-an-image-processing-pipeline-with-python
You can get a much cleaner post-processed image before using Tesseract to OCR the text. Try using the Background Surface Thresholding (BST) technique rather than other simple thresholding methods. You can find a white paper on the subject here.
There is an implementation of BST for OpenCV that works pretty well https://stackoverflow.com/a/22127181/3475075
i needed exactly the same thing and i tried some image optimisations to improve the output
you can find my experiment with tessaract here
https://github.com/aryansbtloe/ExperimentWithTesseract

Saving MATLAB figures as PDF with quality 300 DPI, centered

I want to save a MATLAB figure as PDF, with quality 300 DPI, and centered.
So far I managed to save it, but the image appears cropped. I changed the page type to A3 and kind of solves the problem, but I am looking for something more elegant. I am doing it from the GUI, but maybe from the command line is easier in MATLAB.
Is there any package or script that makes this (fundamental task for publications and papers) a bit easier?
Try using the following command:
print -painters -dpdf -r300 test.pdf
You will, of course, already have to have a file named test.pdf in the current directory.
Some notes on the -commands as well.
-painters: this specifies the use of the painters alogrithm for the exporting.
-dpdf: specifies a vector image, specially a pdf in this case. This is through Ghostscript.
-r300: specifies a 300 dpi resolution. -r400 would be 400 dpi and so on.
On an off note. I tend to just save the figure as a high DPI tiff image and import that tiff into another program where I actually assemble my figure(s) for the paper. I tend to lean towards CorelDraw personally.
I would recommend to check the exportfig package
exportfig(gcf, path_to_file, 'format','pdf','Resolution', 300 )
also, you can check fig package, which is nice to call before the exportfig:
figure
plot(x,y)
fig
exportfig(gcf, path_to_file, 'format','pdf','Resolution', 300 )

Overlaying or merging multiple .ps files

I have used gmt to create several .ps files of x - y graphs with identical axes. I have several sets of data, each containing between 14 and 20 plots. Each plot is in a separate directory.
I would like to overlay every .ps within a dataset, in order to show correlation between the plots.
I know this is similar to the thread posted here:
overlay one pdf or ps file on top of another
but I don't have to deal with multiple pages.
I'm not a programmer, I'm a student! I would really appreciate a quick-ish way to stack them on top of each other to see an overall trend.
If not, I'm off to buy a stack of OHP films and find the nearest photocopier.... which would not look nearly as shiny.
All help is appreciated!
I've done something like this before, using GMT to produce two plots (of opposite sides of the Earth) to PS and overlaying them, one flipped 180 degrees and reflected (that is, depicting the Earth as a projective plane with each point equated with its antipode).
This was my code:
#!/bin/sh
GMT gmtset BASEMAP_FRAME_RGB +192/192/192
GMT gmtset BASEMAP_FRAME_RGB 0/0/0
GMT pscoast -JS-60/0/16 -R0/360/-90/90 -Di -A5000 -N1 -W -GP300/15:FLightRedB- -SWhite -P -K > mapa.ps
GMT pscoast -JS120/0/16 -R0/360/-90/90 -Bg30/g15 -Di -A5000 -N1 -W -GP300/15:FLightGreenB- -Sp1/50:F-B- -P -O > mapb.ps
sed -i 's/595 842/600 600/g' mapa.ps
sed -i 's/PSL/180 rotate -1 1 scale 0 -1890 translate \nPSL/' mapb.ps
cat mapa.ps mapb.ps > mapc.ps
ps2pdf mapc.ps
Commenting out the second sed line overlays them without flipping the second one. You can probably achieve what you want by tweaking this script and replacing the GMT commands with whatever you're using. The -O option used for the second plot sets overlay mode, which omits the PS code that triggers the creation of a new page. Then you can just cat them together.
Well, the Inkscape website says it can import PostScript. take that with a grain of salt, though- I haven't tried it myself.
Alternately, if you don't mind getting your hands a little dirty, PostScript is a fairly human-readable stack based programming language- I highly recommend A First Guide To PostScript. If you can figure out what chunk of the documents contains the plot you want, you ought to be able to copy and paste those together. This all depends heavily upon the quality and organization of code generated by GMT.
Your best bet is probably a vector graphics application like Inkscape (above) or Adobe Illustrator.