资讯专栏INFORMATION COLUMN

怎么使用python对图片进行批量压缩

89542767 / 536人阅读

  小编写这篇文章的主要目的,主要是讲解一些关于python的事情,比如需要对图片进行批量压缩,压缩的方法还是比较的多的,那么,为了提高效率,怎么进行批量压缩呢?下面就给大家详细解答下。


  前言


  最近在研究怎么对图片资源进行无损压缩,网上也找了一些资料。总而言之,收获不少,所以想对最近的学习做个总结。


  无损压缩其实是相对而言的,目的是为了减小图片资源的内存大小但又不影响图片的显示质量。下面我将介绍两种批量压缩图片的方法,方法一是使用python和Pillow模块对图片进行压缩,这个方法对jpeg格式的图片有非常高的压缩效率,但该方法不太适合对png图片进行压缩。另一个方式是使用Python和Selenium模块操纵Squoosh批量压缩图片。


  使用Python和Pillow模块压缩图片


  Pillow是Python上一个功能非常强大的图形处理库,若本地还没安装,可以通过指令:pip install Pillow安装。使用Pillow进行压缩的策略大致总结为三个:1、优化flag,2、渐进式JPEG,3、JPEG动态质量。


  我们先用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、优化flag
  开启optimize设置,这是以CPU耗时为代价节省额外的文件大小,由于本质没变,对图片质量没有丝毫影响。
  ...
  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动态质量


  最广为人知的减小JPEG文件大小的方法就是设置quality。很多应用保存JPEG时都会设置一个特定的质量数值。


  质量其实是个很抽象的概念。实际上,一张JPEG图片的每个颜色通道都有不同的质量。质量等级从0到100在不同的颜色通道上都对应不同的量化表,同时也决定了有多少信息会丢失。


  在信号域量化是JPEG编码中失去信息的第一个步骤。


  我们可以动态地为每一张图片设置最优的质量等级,在质量和文件大小之间找到一个平衡点。我们有以下两种方法可以做到这点:


  Bottom-up:这些算法是在8x8像素块级别上处理图片来生成调优量化表的。它们会同时计算理论质量丢失量和和人眼视觉信息丢失量。


  Top-down:这些算法是将一整张图片和它原版进行对比,然后检测出丢失了多少信息。通过不断地用不同的质量参数生成候选图片,然后选择丢失量最小的那一张。


  我们选择第二种方法:使用二分法在不同的质量等级下生成候选图片,然后使用pyssim计算它的结构相似矩阵(SSIM)来评估每张候选图片损失的质量,直到这个值达到非静态可配置的阈值为止。这个方法让我们可以有选择地降低文件大小(和文件质量),但是只适用于那些即使降低质量用户也察觉不到的图片。


  下面是计算动态质量的代码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
  然后在下面的代码中引用计算动态质量的方法:
  ...
  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是谷歌发布的一款开源的图片在线压缩服务(伪),虽然需要用浏览器打开,但其实是一个整合了许多命令行工具的前端界面,调用的是本地的计算资源,所以只要打开过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

  到此为止,这篇文章就给大家介绍到这里了,希望可以为各位读者带来一定的帮助。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/128239.html

相关文章

  • 10 行 Python 代码,批量压缩图片 500 张,简直太强大了

    摘要:这个网站非常良心,开放了免费的,取消了每张大小的限制,只限定每个月处理张图片。 showImg(https://segmentfault.com/img/remote/1460000019115596?w=4272&h=2848); 本文原创并首发于公众号【Python猫】,未经授权,请勿转载。原文地址:https://mp.weixin.qq.com/s/5hpFDgjCpfb0O1...

    Steven 评论0 收藏0
  • 数据分析遇到PDF文本,怎么Python批量提取内容

    摘要:复杂系统仿真的微博客虚假信息扩散模型研究面向影子分析的社交媒体竞争情报搜集面向人机协同的移动互联网政务门户探析经验证。微博客的企业竞争情报搜集移动社交媒体用户隐私保护对策研究注意这里的提示,原先的个文件没有被再次抽取,只有个新文件被抽取。 showImg(https://segmentfault.com/img/bVbiU7y?w=1000&h=508); 本文为你展示,如何用Pyth...

    cloud 评论0 收藏0
  • 机器学习,了解一下?

    摘要:欢迎常来为什么要学老师上课时候就说过传统算法解决确定性问题,而机器学习解决非确定性问题。机器学习算法机器学习算法和普通算法还是有很大区别的。而自动驾驶等前言机器人,都使用了增强学习。学习资料在线课程入门机器学习经典算法与应用书籍机器学习实战 文章图片来源于 GitHub,网速不佳的朋友请点我看原文。 顺便软广一下个人技术小站:godbmw.com。欢迎常来♪(^∇^*) 1. 为什么要...

    jsbintask 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<