我正在使用Python中的PIL库,我想知道如何确定给定JPG图像的质量。我尝试打开JPG图像做一些事情,并以原始质量再次保存。 Image.save让我确定所需的质量:
im.save(name, quality = x)
但我看不出任何提取原始文件的方法。现在我只是猜测并尝试通过对'质量'参数进行二进制搜索来获得与输入大小相同的输出文件,但这是不可接受的长期解决方案:)
我也试过使用:Image.info但我的大多数图像都没有任何有用的信息(例如:'adobe','icc_profile','exif','adobe_transform')
帮助!
答案 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实例,该实例会丢失一些属性,例如format
和quantization
。
我不得不调查“枕头”源才能弄清楚,但看来您也可以这样做:
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格式。没有办法使颜色质量更高。