简体   繁体   中英

PIL jpeg, how to preserve the pixel color

I have some experiments with JPEG, the doc said "100 completely disables the JPEG quantization stage."

However, I still got some pixel modification during saving. Here is my code:

import Image
red = [20,30,40,50,60,70];
img = Image.new("RGB", [1, len(red)], (255,255,255))
pix = img.load()

for x in range(0,len(red)):
    pix[0,x] = (red[x],255,255)

img.save('test.jpg',quality=100)

img = Image.open('test.jpg')
pix = img.load()

for x in range(0,len(red)):
    print pix[0,x][0],

I got unexpected output: 22 25 42 45 62 65 What should I do to preserve the pixel value ? Please note that I also tried with PHP using imagejpeg and It gives me the correct value when quality=100.

I can use png to preserve, but I want to know the reason behind this and if there is any option to avoid

JPEG will always carry risk of lossyness, see Is Jpeg lossless when quality is set to 100? .

Your best bet is to use another format, especially if your experiments are for science :) Even if you're forced to start with JPEG (which seems unlikely) you should immediately convert to a lossless format for any kind of analysis and modification.

If you really want to try lossless JPEG work with python you can try jpegtran , "the lossless jpeg image transformation software from the Independent Jpeg Group" , but as @Mark notes, this won't get you very far.

By the way, quantization is used in lossy or lossless compression alike, so my guess is that

...100 completely disables the JPEG quantization stage. [1]

simply means that it's not compressed at all.

JPEG consists of many different steps, many of which introduce some loss. By using a sample image containing only red, you've probably run across the worst offender - downsampling or chroma subsampling . Half of the color information is thrown away because the eye is more sensitive to brightness changes than color changes.

Some JPEG encoders can be configured to turn off subsampling, including PIL and Pillow by setting subsampling=0 . In any case it won't give you a completely lossless file since there are still other steps that introduce a loss.

Believe I've figured out how to keep the current color subsampling and other quality details:

from PIL import Image, JpegImagePlugin as JIP

img = Image.open(filename)
img.save(
    filename + '2.jpg',                 # copy
    format='JPEG',
    exif=img.info['exif'],              # keep EXIF info
    optimize=True,
    qtables=img.quantization,           # keep quality
    subsampling=JIP.get_sampling(img),  # keep color res
)

Per https://www.exiv2.org/tags.html I've found that the YCbCrSubSampling tag is not kept in EXIF in JPEG files:

In JPEG compressed data a JPEG marker is used instead of this tag.

This must be why there is another function in a seemingly out of the way place to to grab it.

(Believe I found it here: https://newbedev.com/determining-jpg-quality-in-python-pil )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM