1. 程式人生 > 程式設計 >如何使用Python調整影象大小

如何使用Python調整影象大小

作者|Nicholas Ballard
編譯|VK
來源|Towards Data Science

可以說,每一個“使用計算機的人”都需要在某個時間點調整影象的大小。MacOS的預覽版可以做到,WindowsPowerToys也可以。

本文使用Python來調整影象大小,幸運的是,影象處理和命令列工具是Python的兩個特長。

本文旨在向你展示三件事:

  1. 影象的基本概念。
  2. 用於操作影象的Python庫。
  3. 你可以在自己的專案中使用本文的程式碼。

我們要構建的命令列程式可以一次調整一個或多個影象檔案的大小。

建立影象

在這個例子中,我們將建立我們自己的影象,而不是找到一個真正的影象來操縱。

為什麼?事實上,創造影象是一個很好的方式來說明一個影象實際上是什麼。這個調整大小的程式在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製作影象

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)

如何使用Python調整影象大小

這就是渲染的影象。在背後,資料是這樣的:

[[[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)

如何使用Python調整影象大小

它做了我們所期望的。影象從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)

如何使用Python調整影象大小

請注意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調整影象大小的資料請關注我們其它相關文章!