教你用Python壓縮圖片

品質、速度、廉價,選擇其中兩個

如果需要做圖片識別那麼必定需要大量的訓練素材,我們通常使用爬蟲來獲取,python爬取bing圖片python爬取百度圖片,但是怕取下來的圖片大小不一,再進行訓練之前必須進行裁剪和壓縮,今天就來講一講圖片壓縮,下面這個例子是我做一個項目時用到的

import PIL.Image as Image  import os    #圖片壓縮批處理  def compressImage(srcPath,dstPath):      for filename in os.listdir(srcPath):          #如果不存在目的目錄則創建一個,保持層級結構          if not os.path.exists(dstPath):                  os.makedirs(dstPath)            #拼接完整的文件或文件夾路徑          srcFile=os.path.join(srcPath,filename)          dstFile=os.path.join(dstPath,filename)            # 如果是文件就處理          if os.path.isfile(srcFile):              try:                  #打開原圖片縮小後保存,可以用if srcFile.endswith(".jpg")或者split,splitext等函數等針對特定文件壓縮                  sImg=Image.open(srcFile)                  w,h=sImg.size                  dImg=sImg.resize((int(w/2),int(h/2)),Image.ANTIALIAS)  #設置壓縮尺寸和選項,注意尺寸要用括弧                  dImg.save(dstFile) #也可以用srcFile原路徑保存,或者更改後綴保存,save這個函數後面可以加壓縮編碼選項JPEG之類的                  print (dstFile+" 成功!")              except Exception:                  print(dstFile+"失敗!!!!!!!!!!!!!!!!!!!!!!!!!!!!")            # 如果是文件夾就遞歸          if os.path.isdir(srcFile):              compressImage(srcFile, dstFile)    if __name__=='__main__':      compressImage("G:/兔屎圖片_未處理","G:/兔屎圖片_已處理")

可能這個方法不是很通用,因為我當時處理的圖片都是很大的,一個圖片大概在3M-5M這樣,而我並不需要這麼高解析度,因為太高解析度會影響我機器學習的效率,我就採用最粗暴的方法,使用PIL庫中的Image類,調用resize方法把圖片的寬高直接砍一半,但是這裡我還是採用了Image.ANTIALIAS濾鏡雖然這樣會使我圖片壓縮的效率降低一大截,但也盡最大可能的保留了圖片的資訊。

但我後來又遇到一種更好的壓縮圖片的方法,使用tinify API進行壓縮,通過它壓縮的圖片資訊基本上沒有損失,是個壓縮圖片利它的官方網站:https://tinypng.com/

在它官網上也可以直接進行壓縮,不過只能小批量的操作,一次最多20張,下面是使用它進行圖片壓縮的腳本,你需要自己申請Key填寫到程式中

import os  import os.path  import click  import tinify    tinify.key = "你申請的Key,放在這裡."  targetFileDirName = "/compress" #輸出目錄  targetIsDir = False  totalPicCount = 1 #壓縮圖片總數  compressSuccessPicCount = 0 #圖片壓縮成功的數量    #這裡就是通過tingPng壓縮圖片的核心程式碼  def compress_core(file, outputFile):      source = tinify.from_file(file)  #壓縮指定文件      source.to_file(outputFile)       #將壓縮後的文件輸出當指定位置    def compress_file(file):      if not os.path.isfile(file):          print("你指定的不是文件,不給你壓縮這個文件!")          return      srcFiledirName = os.path.dirname(file)      basename = os.path.basename(file)  #獲得文件全稱 例如  migo.png      filename, fileSuffix = os.path.splitext(basename)  #獲得文件名稱和後綴名  例如 migo 和 png      if picIsCorrect(fileSuffix):          targetFileDir = srcFiledirName + targetFileDirName          if not os.path.isdir(targetFileDir):              os.mkdir(targetFileDir)          print("正在壓縮的圖片:  %s"%(srcFiledirName + "/" +basename))          compress_core(file, targetFileDir + "/" + basename)          global compressSuccessPicCount          compressSuccessPicCount += 1          global targetIsDir          if targetIsDir is not True:              print("------------壓縮的圖片在:  %s  目錄下"%(targetFileDir))      else:          print("暫不支援壓縮 {} 格式的文件, 文件名: {}".format(fileSuffix, basename))    def picIsCorrect(fileSuffix):      if fileSuffix == ".png" or fileSuffix == ".jpg" or fileSuffix == ".jpeg":          return True      else:          return False    def compress_dir(dir):      if not os.path.isdir(dir):          print("你輸入的不是一個目錄")          return      else:          global targetIsDir          targetIsDir = True          srcFilePath = dir #源路徑          for root, dirs, files in os.walk(srcFilePath):              global totalPicCount              totalPicCount = len(files)              for name in files:                  compress_file(srcFilePath + "/" + name)              break #僅遍歷當前目錄      print("------------所有壓縮的圖片都在: %s  目錄下" %(srcFilePath + targetFileDirName))    @click.command()  @click.option('-f', "--file",  type=str,  default=None,  help="單個文件壓縮")  @click.option('-d', "--dir",   type=str,  default=None,  help="被壓縮的文件夾")  def run(file, dir):      if not file is None:          compress_file(file)         #壓縮指定的文件          pass      elif not dir is None:          compress_dir(dir)           #壓縮指定的目錄          pass      else:          compress_dir(os.getcwd())   #壓縮當前文件夾          print("當前目錄: %s"%(os.getcwd()))      print("------壓縮結束!------圖片總數 ({}),  壓縮的圖片數量 ({})".format(totalPicCount, compressSuccessPicCount))    if __name__ == "__main__":      run()