使用Python調整圖像大小

做者|Nicholas Ballard
編譯|VK
來源|Towards Data Sciencehtml

能夠說,每個「使用計算機的人」都須要在某個時間點調整圖像的大小。MacOS的預覽版能夠作到,WindowsPowerToys也能夠。python

本文使用Python來調整圖像大小,幸運的是,圖像處理和命令行工具是Python的兩個特長。算法

本文旨在向你展現三件事:數組

  1. 圖像的基本概念。
  2. 用於操做圖像的Python庫。
  3. 你能夠在本身的項目中使用本文的代碼。

咱們要構建的命令行程序能夠一次調整一個或多個圖像文件的大小。bash

建立圖像

在這個例子中,咱們將建立咱們本身的圖像,而不是找到一個真正的圖像來操縱。app

爲何?事實上,創造圖像是一個很好的方式來講明一個圖像其實是什麼。這個調整大小的程序在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=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...。)

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接受可配置的選項。

請記住,編寫代碼可能須要數小時或數天。但它只需幾毫秒就能夠運行。你製做的程序沒必要很大。任何一件能節省你的時間或讓你產生更多產出的東西,都有可能爲你的餘生服務!

資源

原文連接:https://towardsdatascience.co...

歡迎關注磐創AI博客站:
http://panchuang.net/

sklearn機器學習中文官方文檔:
http://sklearn123.com/

歡迎關注磐創博客資源彙總站:
http://docs.panchuang.net/

相關文章
相關標籤/搜索