作者|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,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,0)
pixel
marigold: Pixel = Pixel(234,162,33)
red: Pixel = Pixel(255,0,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, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[234, 162, 33],
...
現在我們有了一個影像,讓我們調整它的大小!
在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=https://www.cnblogs.com/panchuangai/archive/2020/09/25/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, 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 = Image.open(fp)
width, height = im.size
new_width: int = _scale(width, scale)
new_height: int = _scale(height, scale)
new_dim: tuple = (new_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.com/en/7.x/,)
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, scale: Union[float, int]) -> Image:
""" 調整影像大小,保持其比例
Args:
fp (str): 影像檔案的路徑引數
scale (Union[float, int]): 百分比作為引數,如:53
Returns:
image (np.ndarray): 按比例縮小的圖片
"""
_scale = lambda dim, s: int(dim * s / 100)
im: PIL.Image.Image = Image.open(fp)
width, height = im.size
new_width: int = _scale(width, scale)
new_height: int = _scale(height, scale)
new_dim: tuple = (new_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命令的情況下呼叫腳本,另外,如果你將新的可執行檔案添加到路徑中的檔案夾中,你可以從計算機上的任何位置呼叫此程式,如resize -p *jpg -s 75
結論
本教程進行了大量的研究:
- 首先介紹了一些用于影像處理的第三方Python庫,
- 然后使用Python從頭構建一個影像,以進一步了解影像的實際含義,
- 然后,選擇其中一個選項,并構建一個腳本,在保持影像比例的同時縮小影像,
- 最后,把所有這些放在一個命令列實用程式中,通過click接受可配置的選項,
請記住,撰寫代碼可能需要數小時或數天,但它只需幾毫秒就可以運行,你制作的程式不必很大,任何一件能節省你的時間或讓你產生更多產出的東西,都有可能為你的余生服務!
資源
- click(https://click.palletsprojects.com/en/7.x/)
- matplotlib(https://matplotlib.org/3.2.0/tutorials/introductory/images.html)
- opencv(https://docs.opencv.org/4.4.0/)
- pillow(https://pillow.readthedocs.io/en/stable/)
- scikit-image(https://scikit-image.org/)
原文鏈接:https://towardsdatascience.com/how-to-resize-images-using-python-8aaba74602ed
歡迎關注磐創AI博客站:
http://panchuang.net/
sklearn機器學習中文官方檔案:
http://sklearn123.com/
歡迎關注磐創博客資源匯總站:
http://docs.panchuang.net/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/131604.html
標籤:其他
