如何使用Python調整影象大小
作者|Nicholas Ballard
編譯|VK
來源|Towards Data Science
可以說,每一個“使用計算機的人”都需要在某個時間點調整影象的大小。MacOS的預覽版可以做到,WindowsPowerToys也可以。
本文使用Python來調整影象大小,幸運的是,影象處理和命令列工具是Python的兩個特長。
本文旨在向你展示三件事:
- 影象的基本概念。
- 用於操作影象的Python庫。
- 你可以在自己的專案中使用本文的程式碼。
我們要構建的命令列程式可以一次調整一個或多個影象檔案的大小。
建立影象
在這個例子中,我們將建立我們自己的影象,而不是找到一個真正的影象來操縱。
為什麼?事實上,創造影象是一個很好的方式來說明一個影象實際上是什麼。這個調整大小的程式在Instagram上也同樣適用。
那麼,什麼是影象?在Python資料術語中,影象是int元組的列表。
image = list[list[tuple[*int,float]]]
NumPy的定義是一個二維形狀陣列 (h,w,4),其中h表示高的畫素數(上下),w表示寬的畫素數(從左到右)。
換句話說,影象是畫素列表(行)的列表(整個影象)。每個畫素由3個整數和1個可選浮點陣列成:紅色通道、綠色通道、藍色通道、alpha(浮點可選)。紅色、綠色、藍色通道(RGB)的值從0到255。
從現在開始,我們將討論沒有alpha通道的彩色影象,以保持簡單。Alpha是畫素的透明度。影象也只能有一個值從0到255的通道。這就是灰度影象,也就是黑白影象。在這裡我們使用彩色影象!
import matplotlib as plt pixel: tuple = (200,100,150) plt.imshow([[list(pixel)]])
用純Python製作影象
Python完全能夠建立影象。要顯示它,我將使用matplotlib庫,你可以使用它安裝:
pip install matplotlib
建立畫素:
from dataclasses import dataclass @dataclass class Pixel: red: int green: int blue: int # alpha: float = 1 pixel = Pixel(255,0) pixel # returns: # Pixel(red=255,green=0,blue=0,alpha=1)
建立影象:
from __future__ import annotations from dataclasses import dataclass,astuple from itertools import cycle from typing import List import matplotlib.pyplot as plt import matplotlib.image as mpimg @dataclass class Pixel: red: int green: int blue: int # alpha: float = 1 pixel = Pixel(255,0) pixel marigold: Pixel = Pixel(234,162,33) red: Pixel = Pixel(255,0) Image = List[List[Pixel]] def create_image(*colors: Pixel,blocksize: int = 10,squaresize: int = 9) -> Image: """ 用可配置的畫素塊製作一個正方形影象(寬度和高度相同). Args: colors (Pixel): 可迭代的顏色呈現順序的引數。 blocksize (int,optional): [description]. 預設10. squaresize (int,optional): [description]. 預設9. Returns: Image: 一幅漂亮的正方形圖片! """ img: list = [] colors = cycle(colors) for row in range(squaresize): row: list = [] for col in range(squaresize): color = next(colors) # 設定顏色 for _ in range(blocksize): values: list[int] = list(astuple(color)) row.append(values) [img.append(row) for _ in range(squaresize)] # 建立行高 return img if __name__ == '__main__': image = create_image(marigold,red) plt.imshow(image)
這就是渲染的影象。在背後,資料是這樣的:
[[[234,33],[234,[255,0],...
在Python中調整大小
在Python中編寫調整影象大小的演算法實際上有很多的工作量。
在影象處理演算法中有很多內容,有些人為此貢獻了十分多的工作。例如重取樣——在縮小後的影象中使用一個畫素來代表周圍的高解析度畫素。影象處理是一個巨大的話題。如果你想親眼看看,看看Pillow的Image.py,它在路徑path/to/site-packages/PIL中。
這中間還有一些優化,比如抗鋸齒和減少間隙…這裡的內容非常多。我們是站在巨人的肩膀上,可以用一行程式碼來解決我們的問題。
如果你有興趣瞭解更多有關處理影象時幕後發生的事情,我鼓勵你更多地檢視“機器視覺”主題!這絕對是一個蓬勃發展的領域。
做得足夠好,就會有很多公司願意為你的計算機視覺專業知識付出最高的代價。自動駕駛,IOT,監視,你命名它;所有基本上依賴於處理圖片(通常在Python或C++)。
一個很好的起點是檢視scikit image。
OpenCV
OpenCV可以用來作影象處理。他使用C++編寫並移植到了Python
import cv2 def resize(fp: str,scale: Union[float,int]) -> np.ndarray: """ 調整影象大小,保持其比例 Args: fp (str): 影象檔案的路徑引數 scale (Union[float,int]): 百分比作為引數。如:53 Returns: image (np.ndarray): 按比例縮小的圖片 """ _scale = lambda dim,s: int(dim * s / 100) im: np.ndarray = cv2.imread(fp) width,height,channels = im.shape new_width: int = _scale(width,scale) new_height: int = _scale(height,scale) new_dim: tuple = (new_width,new_height) return cv2.resize(src=im,dsize=new_dim,interpolation=cv2.INTER_LINEAR)
interpolation引數的選項是cv2包中提供的flags之一:
INTER_NEAREST – 近鄰插值
INTER_LINEAR – 雙線性插值(預設使用)
INTER_AREA – 利用畫素區域關係重新取樣。它可能是影象抽取的首選方法。但是當影象被縮放時,它類似於INTER_NEAREST方法。
INTER_CUBIC – 一個大於4×4畫素鄰域的雙三次插值
INTER_LANCZOS4 – 一個大於8×8畫素鄰域的Lanczos插值
返回後:
resized = resize("checkers.jpg",50) print(resized.shape) plt.imshow(resized) # 也可以使用 cv2.imshow("name",image)
它做了我們所期望的。影象從900畫素高,900畫素寬,到450×450(仍然有三個顏色通道)。因為Jupyter Lab的matplotlib著色,上面的螢幕截圖看起來不太好。
Pillow
pillow庫在Image類上有一個調整大小的方法。它的引數是:
size: (width,height)
resample: 預設為BICUBIC. 重取樣演算法需要的引數。
box: 預設為None。為一個4元組,定義了在引數(0,0,寬度,高度)內工作的影象矩形。
reducing_gap: 預設為None。重新取樣優化演算法,使輸出看起來更好。
以下是函式:
from PIL import Image def resize(fp: str,int]): 百分比作為引數。如:53 Returns: image (np.ndarray): 按比例縮小的圖片 """ _scale = lambda dim,s: int(dim * s / 100) im = Image.open(fp) width,height = im.size new_width: int = _scale(width,new_height) return im.resize(new_dim)
使用Pillow 的函式與OpenCV非常相似。唯一的區別是PIL.Image.Image類具有用於訪問影象(寬度、高度)的屬性大小。
結果是:
resized = resize("checkers.jpg",30.5) print(resized.size) resized.show("resized image",resized)
請注意show方法如何開啟作業系統的預設程式以檢視影象的檔案型別。
建立命令列程式
現在我們有了一個調整影象大小的函式,現在是時候讓它有一個執行調整大小的使用者介面了。
調整一個影象的大小是可以的。但我們希望能夠批量處理影象。
我們將要構建的介面將是最簡單的介面:命令列實用程式。
Pallets專案是Flask背後的天才社群,是一個Jinja模板引擎:Click(https://click.palletsprojects...。)
pip install click
Click是一個用於製作命令列程式的庫。這比使用普通的argparse或在if __name__ == '__main__':中啟動一些if-then邏輯要好得多。所以,我們將使用Click來裝飾我們的影象調整器。
下面是從命令列調整影象大小的完整指令碼!
""" resize.py """ from __future__ import annotations import os import glob from pathlib import Path import sys import click from PIL import Image """ 文件: https://pillow.readthedocs.io/en/5.1.x/handbook/image-file-formats.html """ SUPPORTED_FILE_TYPES: list[str] = [".jpg",".png"] def name_file(fp: Path,suffix) -> str: return f"{fp.stem}{suffix}{fp.suffix}" def resize(fp: str,int]) -> Image: """ 調整影象大小,保持其比例 Args: fp (str): 影象檔案的路徑引數 scale (Union[float,s: int(dim * s / 100) im: PIL.Image.Image = Image.open(fp) width,new_height) return im.resize(new_dim) @click.command() @click.option("-p","--pattern") @click.option("-s","--scale",default=50,help="Percent as whole number to scale. eg. 40") @click.option("-q","--quiet",default=False,is_flag=True,help="Suppresses stdout.") def main(pattern: str,scale: int,quiet: bool): for image in (images := Path().glob(pattern)): if image.suffix not in SUPPORTED_FILE_TYPES: continue im = resize(image,scale) nw,nh = im.size suffix: str = f"_{scale}_{nw}x{nh}" resize_name: str = name_file(image,suffix) _dir: Path = image.absolute().parent im.save(_dir / resize_name) if not quiet: print( f"resized image saved to {resize_name}.") if images == []: print(f"No images found at search pattern '{pattern}'.") return if __name__ == '__main__': main()
命令列程式從入口點函式main執行。引數通過傳遞給click.option選項:
- pattern採用字串形式來定位與指令碼執行的目錄相關的一個或多個影象。--pattern="../catpics/*.png將向上一級查詢catpics資料夾,並返回該資料夾中具有.png影象副檔名的所有檔案。
- scale接受一個數字、浮點或整數,並將其傳遞給resize函式。這個指令碼很簡單,沒有資料驗證。如果你新增到程式碼中,檢查比例是一個介於5和99之間的數字(合理的縮小比例引數)。你可以通過-s "chicken nuggets"進行設定。
- 如果不希望在程式執行時將文字輸出到標準流,則quiet是一個選項引數。
從命令列執行程式:
python resize.py -s 35 -p "./*jpg"
結果:
$ py resize.py -p "checkers.jpg" -s 90
resized image saved to checkers_90_810x810.jpg.
正在檢查資料夾:
$ ls -lh checkers*
-rw-r--r-- 1 nicho 197609 362K Aug 15 13:13 checkers.jpg
-rw-r--r-- 1 nicho 197609 231K Aug 15 23:56 checkers_90_810x810.jpg
不錯!所以程式縮小了影象,給了它一個描述性的標籤,我們可以看到檔案大小從362KB到231KB!
為了檢視程式同時處理多個檔案,我們將再次執行它:
$ py resize.py --pattern="checkers*" --scale=20
resized image saved to checkers_20_180x180.jpg.
resized image saved to checkers_90_810x810_20_162x162.jpg.
檔案系統輸出:
$ ll -h checkers*
-rw-r--r-- 1 nicho 197609 362K Aug 15 13:13 checkers.jpg
-rw-r--r-- 1 nicho 197609 1.8K Aug 16 00:23 checkers_20_180x180.jpg
-rw-r--r-- 1 nicho 197609 231K Aug 15 23:56 checkers_90_810x810.jpg
-rw-r--r-- 1 nicho 197609 1.8K Aug 16 00:23 checkers_90_810x810_20_162x162.jpg
只要匹配到了模式,遞迴可以處理任意數量的影象。
Click
Click 是一個神奇的工具。它可以包裝一個函式並在一個模組中以“正常的方式”從一個if __name__ == '__main__'語句執行。(實際上,它甚至不需要這樣做;你只需定義和裝飾要執行的函式即可),但它真正的亮點在於將指令碼作為包安裝。
這是通過Python附帶的setuptools庫完成的。
這是我的setup.py.
from setuptools import setup setup( name='resize',version='0.0.1',py_modules=['resize'],install_requires=[ 'click','pillow',],entry_points=''' [console_scripts] resize=resize:main ''' )
使用以下命令生成可執行檔案/包裝包:
pip install -e .
結論
本教程進行了大量的研究:
- 首先介紹了一些用於影象處理的第三方Python庫。
- 然後使用Python從頭構建一個影象,以進一步瞭解影象的實際含義。
- 然後,選擇其中一個選項,並構建一個指令碼,在保持影象比例的同時縮小影象。
- 最後,把所有這些放在一個命令列實用程式中,通過click接受可配置的選項。
請記住,編寫程式碼可能需要數小時或數天。但它只需幾毫秒就可以執行。你製作的程式不必很大。任何一件能節省你的時間或讓你產生更多產出的東西,都有可能為你的餘生服務!
原文連結:
https://towardsdatascience.co...
以上就是如何使用Python調整影象大小的詳細內容,更多關於Python調整影象大小的資料請關注我們其它相關文章!