我想使用 python 压缩内存中的图像。
使用答案中的代码https://stackoverflow.com/a/40768705我希望更改“质量参数”(90)我会得到更小的结果图像。
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
result, enc_img = cv2.imencode('.jpg', img_np, encode_param)
我最初的计划是降低这个“质量参数”,直到获得所需的图像尺寸。 像这样:
def compress_img(img: bytes, max_size: int = 102400):
"""
@param max_size: maximum allowed size in bytes
"""
quality = 90
while len(img) > max_size:
img = _compress_img(img, quality=quality)
quality -= 5
if quality < 0:
raise ValueError(f"Too low quality: {quality}")
return img
但是在运行一些测试之后,我实际上得到的结果图像比原始图像更大。我不明白原始大小如何小于压缩后的大小。这个逻辑有什么问题吗?
original size: 125.07 kb
load to cv2 size: 4060.55 kb
compressed size: 186.14 kb
这是完整代码:
import cv2
import requests
import numpy as np
def request_img(img_url: str) -> bytes:
r = requests.get(img_url, stream=True)
img = r.raw.read()
return img
if __name__ == '__main__':
url = "https://m.media-amazon.com/images/I/71bUROETvoL._AC_SL1500_.jpg"
img_bytes = request_img(url)
# the original size of image is 128073 bytes `len(img_bytes)`
with open("__img_orig.jpg", "wb") as f:
f.write(img_bytes)
print(f"original size: {round(len(img_bytes)/ 1024, 2)} kb")
# after I load image to cv2 - it becomes `4158000` bytes
image_np = np.frombuffer(img_bytes, np.uint8)
img_np = cv2.imdecode(image_np, cv2.IMREAD_COLOR)
print(f"load to cv2 size: {round(len(img_np.tobytes()) / 1024, 2)} kb")
# resulting "compressed" size is `190610` bytes which is 48% more than original sie. How can it be???
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
result, enc_img = cv2.imencode('.jpg', img_np, encode_param)
res_img_bytes = enc_img.tobytes()
print(f"compressed size: {round(len(res_img_bytes) / 1024, 2)} kb")
with open("__img_compress.jpg", "wb") as f:
f.write(res_img_bytes)
原始 JPEG 压缩质量为 81,大小为 125kB。请参阅下面的方法来获得质量评估。
图像为 1500x924 RGB 像素,因此解压后将占用内存 1500x924x3 字节,即 4,158,000 字节。
你用质量 90 压缩它,得到了 186kB,这是可以预料的,因为原始质量是 81,即更低。
以 90 质量压缩它是毫无意义的,无论如何你都无法恢复超过 81 的质量。失去的就是失去了。
您可以使用以下方法确定 JPEG 编码的质量:
exiftool -JPEGQualityEstimate IMAGE.JPG
或者使用 ImageMagick 如下:
magick IMAGE.JPG -format %Q info: