如何使用python對圖片進行批量壓縮詳解
前言
最近在研究怎么對圖片資源進行無損壓縮,網上也找了一些資料??偠灾?,收獲不少,所以想對最近的學習做個總結。
無損壓縮其實是相對而言的,目的是為了減小圖片資源的內存大小但又不影響圖片的顯示質量。下面我將介紹兩種批量壓縮圖片的方法,方法一是使用python和Pillow模塊對圖片進行壓縮,這個方法對jpeg格式的圖片有非常高的壓縮效率,但該方法不太適合對png圖片進行壓縮。另一個方式是使用Python和Selenium模塊操縱Squoosh批量壓縮圖片。
使用Python和Pillow模塊壓縮圖片
Pillow是Python上一個功能非常強大的圖形處理庫,若本地還沒安裝,可以通過指令:pip install Pillow安裝。使用Pillow進行壓縮的策略大致總結為三個:1、優(yōu)化flag,2、漸進式JPEG,3、JPEG動態(tài)質量。
我們先用Python寫一個簡單的保存圖片的例子:
from PIL import Image
from io import StringIO
import dynamic_quality
im = Image.open("photo.jpg")
print(im.format,im.size,im.mode)
new_photo = im.copy()
new_photo.thumbnail(im.size,resample=Image.ANTIALIAS)
save_args = {'format':im.format}
if im.format=='JPEG':
save_args['quality'].value=85
new_photo.save("copy_photo.jpg",**save_args)1、優(yōu)化flag
開啟optimize設置,這是以CPU耗時為代價節(jié)省額外的文件大小,由于本質沒變,對圖片質量沒有絲毫影響。
...
if im.format=='JPEG':
save_args['quality'].value=85
save_args['optimize']=True
...2、漸進式JPEG
當我們將一張圖片保存為 JPEG 時,你可以從下面的選項中選擇不同的類型:
- 標準型: JPEG 圖片自上而下載入。
- 漸進式: JPEG 圖片從模糊到清晰載入。
漸進式的選項可以在 Pillow 中輕松的啟用 (progressive=True)。漸進式文件的被打包時會有一個小幅的壓縮。
...
if im.format=='JPEG':
save_args['quality'].value=85
save_args['optimize']=True
save_args['progressive=True']=True
...3、JPEG動態(tài)質量
最廣為人知的減小 JPEG 文件大小的方法就是設置 quality。很多應用保存 JPEG 時都會設置一個特定的質量數值。
質量其實是個很抽象的概念。實際上,一張 JPEG 圖片的每個顏色通道都有不同的質量。質量等級從 0 到 100 在不同的顏色通道上都對應不同的量化表,同時也決定了有多少信息會丟失。
在信號域量化是 JPEG 編碼中失去信息的第一個步驟。
我們可以動態(tài)地為每一張圖片設置最優(yōu)的質量等級,在質量和文件大小之間找到一個平衡點。我們有以下兩種方法可以做到這點:
Bottom-up: 這些算法是在 8x8 像素塊級別上處理圖片來生成調優(yōu)量化表的。它們會同時計算理論質量丟失量和和人眼視覺信息丟失量。
Top-down: 這些算法是將一整張圖片和它原版進行對比,然后檢測出丟失了多少信息。通過不斷地用不同的質量參數生成候選圖片,然后選擇丟失量最小的那一張。
我們選擇第二種方法:使用二分法在不同的質量等級下生成候選圖片,然后使用 pyssim 計算它的結構相似矩陣 (SSIM) 來評估每張候選圖片損失的質量,直到這個值達到非靜態(tài)可配置的閾值為止。這個方法讓我們可以有選擇地降低文件大?。ê臀募|量),但是只適用于那些即使降低質量用戶也察覺不到的圖片。
下面是計算動態(tài)質量的代碼dynamic_quality.py:
import PIL.Image
from math import log
from SSIM_PIL import compare_ssim
def get_ssim_at_quality(photo, quality):
"""Return the ssim for this JPEG image saved at the specified quality"""
ssim_photo = "tmp.jpg"
# optimize is omitted here as it doesn't affect
# quality but requires additional memory and cpu
photo.save(ssim_photo, format="JPEG", quality=quality, progressive=True)
ssim_score = compare_ssim(photo, PIL.Image.open(ssim_photo))
return ssim_score
def _ssim_iteration_count(lo, hi):
"""Return the depth of the binary search tree for this range"""
if lo >= hi:
return 0
else:
return int(log(hi - lo, 2)) + 1
def jpeg_dynamic_quality(original_photo):
"""Return an integer representing the quality that this JPEG image should be
saved at to attain the quality threshold specified for this photo class.
Args:
original_photo - a prepared PIL JPEG image (only JPEG is supported)
"""
ssim_goal = 0.95
hi = 85
lo = 80
# working on a smaller size image doesn't give worse results but is faster
# changing this value requires updating the calculated thresholds
photo = original_photo.resize((400, 400))
# if not _should_use_dynamic_quality():
# default_ssim = get_ssim_at_quality(photo, hi)
# return hi, default_ssim
# 95 is the highest useful value for JPEG. Higher values cause different behavior
# Used to establish the image's intrinsic ssim without encoder artifacts
normalized_ssim = get_ssim_at_quality(photo, 95)
selected_quality = selected_ssim = None
# loop bisection. ssim function increases monotonically so this will converge
for i in range(_ssim_iteration_count(lo, hi)):
curr_quality = (lo + hi) // 2
curr_ssim = get_ssim_at_quality(photo, curr_quality)
ssim_ratio = curr_ssim / normalized_ssim
if ssim_ratio >= ssim_goal:
# continue to check whether a lower quality level also exceeds the goal
selected_quality = curr_quality
selected_ssim = curr_ssim
hi = curr_quality
else:
lo = curr_quality
if selected_quality:
return selected_quality, selected_ssim
else:
default_ssim = get_ssim_at_quality(photo, hi)
return hi, default_ssim然后在下面的代碼中引用計算動態(tài)質量的方法:
...
if im.format=='JPEG':
save_args['quality'],value=dynamic_quality.jpeg_dynamic_quality(im)
save_args['optimize']=True
save_args['progressive']=True
...使用Python和Selenium模塊操縱Squoosh批量壓縮圖片
Squoosh 是谷歌發(fā)布的一款開源的圖片在線壓縮服務(偽),雖然需要用瀏覽器打開,但其實是一個整合了許多命令行工具的前端界面,調用的是本地的計算資源,所以只要打開過Squoosh一次,之后都會秒開,并且離線使用。不過最大的缺點就是不可以批量處理,如果我們要處理大量的圖片資源,一張張地進行壓縮處理將會消耗大量的人力成本和時間成本,這明顯是不能接受的。我們要解決的問題就是寫一個腳本來模擬瀏覽器的操作,使我們的雙手得到解放。
Python 調用 Selenium
這是 Squoosh 的主界面,Select an Image 其實是一個輸入框,那我們直接用 Selenium 把本地圖片的路徑輸入進去就行了:

輸入圖片路徑之后就會默認壓縮成 75% 質量的 MozJPEG,我覺得無論是壓縮比和質量都很不錯,所以就沒有改,等待頁面加載完成之后就直接下載:

我們可以認為出現 "..% smaller" 就算是壓縮完成,這時候直接點擊右邊的下載按鈕即可。
代碼:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
import os
import re
driver = webdriver.Chrome('C:/Users/admin/AppData/Local/Google/Chrome/Application/chromedriver.exe')
# 列出目錄下所有的圖片,存在 images 這個列表中
images = os.listdir('C:/Users/admin/Pictures/Saved Pictures')
# 處理所有圖片
for i in range(len(images)):
# 構建圖片路徑
path = 'C:/Users/admin/Pictures/Saved Pictures/' + images[i]
# 嘗試處理所有圖片
try:
# 打開 Squoosh
driver.get('https://squoosh.app')
# 找到輸入框
input_box = driver.find_element_by_xpath('.//input[@class="_2zg9i"]')
# 輸入圖片路徑
input_box.send_keys(path)
#設置圖片格式
select1 = Select(driver.find_elements_by_css_selector('select')[-1])
if re.match('.*.png',images[i]):
select1.select_by_value("png")
if re.match('.*.jpg',images[i]):
select1.select_by_value("mozjpeg")
# 等待出現 'smaller'字樣,10秒不出現則視為處理失敗
locator = (By.XPATH, './/span[@class="_1eNmr _1U8bE"][last()]')
WebDriverWait(driver, 25).until(EC.text_to_be_present_in_element(locator, 'smaller'))
# 找到下載按鈕
button = driver.find_elements_by_xpath('.//a[@title="Download"]')[-1]
# 點擊下載按鈕
button.click()
# 輸出處理失敗的圖片路徑
except:
print('*'*30)
print('Error: '+ path +' failed!')
print('*'*30)
continue總結
到此這篇關于如何使用python對圖片進行批量壓縮的文章就介紹到這了,更多相關python圖片批量壓縮內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Anaconda+pycharm安裝及環(huán)境配置全過程
在使用pyCharm進行開發(fā)時,需要用到Anaconda創(chuàng)建的環(huán)境,下面這篇文章主要給大家介紹了關于Anaconda+pycharm安裝及環(huán)境配置的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-09-09
Python連接MySQL并使用fetchall()方法過濾特殊字符
這篇文章主要介紹了Python連接MySQL的方法并講解了如何使用fetchall()方法過濾特殊字符,示例環(huán)境為Ubuntu操作系統(tǒng),需要的朋友可以參考下2016-03-03
詳解pyenv下使用python matplotlib模塊的問題解決
這篇文章主要介紹了詳解pyenv下使用python matplotlib模塊的問題解決,非常具有實用價值,需要的朋友可以參考下2018-11-11

