[Image-SIG] How to get quality of picture

Franz Buchinger fbuchinger at gmail.com
Mon Oct 12 14:55:47 CEST 2009


As Frederik already mentioned, you can extract the quantisation table of an
opened JPEG file with the .quantization attribute.
To determine the quality setting of the jpeg, you can calculate some hash
(e.g. md5) for the quantisation table and compare it to hashes from jpeg
files saved at different quality settings.

PIL and most other FOSS image processing apps (GIMP, Imagemagick) depend on
libjpeg and its builtin quantisation tables. This means that you can easily
determine the quality of images processed with these apps.
JPEGs saved in commercial apps like Photoshop, Lightroom or directly taken
from a camera however bring their own quality settings and quantisation
tables. An image exported with the "Save for Web" dialog in Photoshop for
example can come in 12 different quality settings, each corresponding to a
different quantisation table which have nothing in common with the ones
libjpeg is using.

In short words: you need a huge database of quantisation table hashes to
reliably identify the quality setting of an arbitrary jpeg. Therefore, I
recommend to make use of exiftool's jpegdigest database, which holds
thousands of quantisation table hashes:

http://cpansearch.perl.org/src/EXIFTOOL/Image-ExifTool-7.89/lib/Image/ExifTool/JPEGDigest.pm

You only have to port the jpegdigest hashing algorithm from perl to python
and convert the database to a dictionary.

kind regards,

Franz

2009/9/29 David Berthelot <d_berthelot at yahoo.com>

> Here's some code that does the trick.
>
> It returns a tuple:
> (coefficient, (luminance_coefficient,luminance_error),
> (chrominance_coefficient,chrominance_error))
>
> Note:
> - The 2nd and 3rd returned items are only useful if you're interested in
> the error (sometimes the error is 0 if the program used a JPEG table that is
> the same as the one used by PIL).
> - Fredrik: You can freely use the code and embed it in PIL if you're
> satisfied with its quality
>
> Code:
> def get_jpeg_quantization_tables(f):
>     """Returns the JPEG quantization tables of a filename or file
> descriptor"""
>     from functools import partial
>     import Image
>     import numpy as N
>     fd    = Image.open(f)
>     if fd.format == 'BMP':
>         return N.ones((8,8)),N.ones((8,8))
>     q     = fd.quantization
>     ql,qc =
> map(partial(N.array,dtype='uint8'),(q.get(0,N.zeros(64)),q.get(1,N.zeros(64))))
>     # Now reorder the JPEG quantification coefficients as 8x8 matrices
>     jpeg_natural_order = N.array([ 0,  1,  8, 16,  9,  2,  3, 10, 17, 24,
> 32, 25, 18, 11,  4,  5, 12,
>                                    19, 26, 33, 40, 48, 41, 34, 27, 20, 13,
> 6,  7, 14, 21, 28, 35, 42,
>                                    49, 56, 57, 50, 43, 36, 29, 22, 15, 23,
> 30, 37, 44, 51, 58, 59, 52,
>                                    45, 38, 31, 39, 46, 53, 60, 61, 54, 47,
> 55, 62, 63])
>     rql = N.zeros(64,'f')
>     rqc = N.zeros(64,'f')
>     for x,y in N.ndenumerate(jpeg_natural_order):
>         rql[y] = ql[x]
>         rqc[y] = qc[x]
>     return rql.reshape(8,8),rqc.reshape(8,8) # Luminance/Chrominance
>
> def guess_jpeg_quality(f,ctables=[]):
>     from StringIO import StringIO
>     import numpy as N
>     import Image
>     # Compute the tables for quality = 1..100 by saving fakes files in
> memory
>     if not ctables:
>         tables = N.zeros((100,2,8,8),'f')
>         for x in xrange(100):
>             fd = StringIO()
>             Image.new('RGB',(64,64)).save(fd,"jpeg",quality=1+x)
>             fd.seek(0)
>             ql,qc = get_jpeg_quantization_tables(fd)
>             tables[x][0] = ql
>             tables[x][1] = qc
>         ctables.append(tables)
>     else:
>         tables = ctables[0]
>     # Use a weighting matrix w to put more emphasis on the comparison of
> lower DCT harmonics
>     w     = 1./N.outer(1+N.arange(8)/7.,1+N.arange(8)/7.)
>     ql,qc = get_jpeg_quantization_tables(f)
>     # Compute errors on Luminance and Chrominance tables
>     errsl,errsc = [],[]
>     for x in xrange(100):
>         errsl.append((N.square((ql-tables[x][0])*w).mean(),x))
>         errsc.append((N.square((qc-tables[x][1])*w).mean(),x))
>     # Select minimal error coefficients
>     lmin = min(errsl)
>     cmin = min(errsc)
>     # Weight coefficients average (more emphasis put on luminance since it
> affects most visual perception)
>     q = int(round(lmin[1]*.8 + cmin[1]*.2))
>     return q,lmin,cmin
>
>
>
> ------------------------------
> *From:* Fredrik Lundh <fredrik at pythonware.com>
> *To:* qiaohl <qiaohl at ucweb.com>
> *Cc:* image-sig <image-sig at python.org>
> *Sent:* Monday, September 28, 2009 5:43:00 AM
> *Subject:* Re: [Image-SIG] How to get quality of picture
>
> The quality setting is used to create a quantization table which is
> then used by the compression algorithm.  There's no pre-defined
> mapping between quality and the contents of the quantization table for
> JPEG (different implementations do different things), but some
> applications attempt to guess by comparing the quantization tables in
> the file with known mapping algorithms.  I'm not aware of any such
> code for Python.
>
> If you want to tinker with this, you can access the quantization table
> of an opened JPEG file via the "quantization" attribute.
>
> </F>
>
> On Mon, Sep 28, 2009 at 9:08 AM, qiaohl <qiaohl at ucweb.com> wrote:
> > Hi,all
> >    Is there any function in PIL to get the value of JPEG quality(1-100)?
> I
> > know there are functions to set this value, But I found no function to
> get
> > this value of an existing JPEG file.
> >
> > Thanks!
> >
> >
> > 2009-09-28
> > ________________________________
> > qiaohl
> > _______________________________________________
> > Image-SIG maillist  -  Image-SIG at python.org
> > http://mail.python.org/mailman/listinfo/image-sig
> >
> >
> _______________________________________________
> Image-SIG maillist  -  Image-SIG at python.org
> http://mail.python.org/mailman/listinfo/image-sig
>
>
> _______________________________________________
> Image-SIG maillist  -  Image-SIG at python.org
> http://mail.python.org/mailman/listinfo/image-sig
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/image-sig/attachments/20091012/f1edca2e/attachment.htm>


More information about the Image-SIG mailing list