用Python确定JPG质量(PIL)

时间:2010-12-04 16:37:28

标签: python image jpeg

我正在使用Python中的PIL库,我想知道如何确定给定JPG图像的质量。我尝试打开JPG图像做一些事情,并以原始质量再次保存。 Image.save让我确定所需的质量:

im.save(name, quality = x)  

但我看不出任何提取原始文件的方法。现在我只是猜测并尝试通过对'质量'参数进行二进制搜索来获得与输入大小相同的输出文件,但这是不可接受的长期解决方案:)
我也试过使用:Image.info但我的大多数图像都没有任何有用的信息(例如:'adobe','icc_profile','exif','adobe_transform')
帮助!

5 个答案:

答案 0 :(得分:26)

在PIL(以及大多数使用libjpeg的所有软件/库)中,质量设置用于构建量化表(ref.)。在libjpeg中,质量数“缩放”样本表值(来自JPEG规范第K.1节)。在其他图书馆里,不同的表格分配不同的质量(例如:Photoshop,数码相机)。

因此,在其他方面,质量等于量化表,所以它比一个数字更复杂。

如果要以相同的“质量”保存修改图像,则只需使用相同的量化表。幸运的是,量化表嵌入在每个JPEG中。不幸的是,在PIL中保存时无法指定量化表。 cjpeg,libjpeg附带的命令行实用程序,可以做到这一点。

这是一些使用指定量化表保存jpeg的粗略代码:

from subprocess import Popen, PIPE
from PIL import Image, ImageFilter

proc = Popen('%s -sample 1x1 -optimize -progressive -qtables %s -outfile %s' % ('path/to/cjpeg', '/path/ta/qtable', 'out.jpg'), shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
P = '6'
if im.mode == 'L':
    P = '5'
stdout, stderr = proc.communicate('P%s\n%s %s\n255\n%s' % (P, im.size[0], im.size[1], im.tostring()))

您需要找到从原始jpeg中提取量化表的方法。 djpeg可以做到这一点(libjpeg的一部分):

djpeg -verbose -verbose image.jpg > /dev/null

您还需要查找和设置采样。有关该支票here的更多信息。您还可以查看test_subsampling

<强>更新

我做了一个PIL分支,增加了在保存JPEG时指定子采样或量化表或两者的可能性。您还可以在保存时指定quality='keep',并使用与原始图像相同的量化表和子采样保存图像(原始图像需要为JPEG)。还有一些预设(基于Photoshop),您可以在保存时传递质量。 My fork.

更新2

我的代码现在是Pillow 2.0的一部分。所以就这样做:

pip install Pillow

答案 1 :(得分:4)

质量是用于生成存储在JPEG中的数据的东西。此编号不存储在JPEG中。

您可以确定质量的一种方法是在编辑之前拍摄图像的8x8像素单元格,然后运行JPEG压缩公式以接近原始图像。您需要开发一个距离函数,从结果到原始(像素差异)。

您仍然会使用质量进行二元搜索,但这项工作量要少得多。

以下是有关JPEG压缩如何工作的信息

https://www.dspguide.com/ch27/6.htm

这是MS常见问题解答的另一种方式

https://support.microsoft.com/kb/324790

你必须从C#翻译。

答案 2 :(得分:0)

我已经使用PIL 5.1测试了quality ='keep'关键字。它产生与默认质量完全相同的结果,即75.

from PIL import Image
img=Image.open('yy.jpg')
img.save('xx.jpg', quality='keep')
img.save('xx1.jpg', quality=75)
img.save('xx2.jpg') # no quality keyword so default is applied

import sh
for i, f in enumerate(('yy.jpg', 'xx1.jpg', 'xx2.jpg')):
    try:
        a = ('xx.jpg', f)
        r = sh.diff(*a)
    except sh.ErrorReturnCode as e:
        r = e.stdout
    r = r.rstrip()
    r = r if r else 'are the same'
    print i, a, r

答案 3 :(得分:0)

在将quality='keep'与某些PIL操作结合使用时,我遇到了问题,因为例如在rotate()transpose()期间,正在创建一个新的Image实例,该实例会丢失一些属性,例如formatquantization

我不得不调查“枕头”源才能弄清楚,但看来您也可以这样做:

def _save_image_matching_quality(img, original_img, fp):
    frmt = original_img.format

    if frmt == 'JPEG':
        quantization = getattr(original_img, 'quantization', None)
        subsampling = JpegImagePlugin.get_sampling(original_img)
        quality = 100 if quantization is None else 0
        img.save(fp, format=frmt, subsampling=subsampling, qtables=quantization, quality=quality)
    else:
        img.save(fp, format=frmt, quality=100)

它应该执行quality='keep'所做的所有事情:)

尽管如此,确切的代码可能并不适合每个用例,您可能需要对其进行调整。我试图实现的目标是尽可能节省空间,但又不影响图像质量,这是最高优先级。

对于一般用例,这可能更好:

def _save_image_matching_quality(img, original_img, fp):
    frmt = original_img.format

    if frmt == 'JPEG':
        quantization = getattr(original_img, 'quantization', None)
        subsampling = JpegImagePlugin.get_sampling(original_img)
        img.save(fp, format=frmt, subsampling=subsampling, qtables=quantization)
    else:
        img.save(fp, format=frmt)

答案 4 :(得分:-3)

据我所知,这是不可能的。通过删除75%的颜色数据或简化颜色来压缩JPEG格式。没有办法使颜色质量更高。