如何使用Python调整图像大小


Posted in Python onSeptember 26, 2020

作者|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,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)

如何使用Python调整图像大小

这就是渲染的图像。在背后,数据是这样的:

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

如何使用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, 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)

如何使用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, 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库。
  • 然后使用Python从头构建一个图像,以进一步了解图像的实际含义。
  • 然后,选择其中一个选项,并构建一个脚本,在保持图像比例的同时缩小图像。
  • 最后,把所有这些放在一个命令行实用程序中,通过click接受可配置的选项。

请记住,编写代码可能需要数小时或数天。但它只需几毫秒就可以运行。你制作的程序不必很大。任何一件能节省你的时间或让你产生更多产出的东西,都有可能为你的余生服务!

原文链接:

https://towardsdatascience.co...

以上就是如何使用Python调整图像大小的详细内容,更多关于Python调整图像大小的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python编程pygal绘图实例之XY线
Dec 09 Python
python读取文件名称生成list的方法
Apr 27 Python
python实现屏保计时器的示例代码
Aug 08 Python
python 实现数字字符串左侧补零的方法
Dec 04 Python
python读写csv文件方法详细总结
Jul 05 Python
Python基于Tensor FLow的图像处理操作详解
Jan 15 Python
python yield和Generator函数用法详解
Feb 10 Python
浅谈python的elementtree模块处理中文注意事项
Mar 06 Python
python中Ansible模块的Playbook的具体使用
May 28 Python
去除python中的字符串空格的简单方法
Dec 22 Python
Python基础之教你怎么在M1系统上使用pandas
May 08 Python
python APScheduler执行定时任务介绍
Apr 19 Python
小白教你PyCharm从下载到安装再到科学使用PyCharm2020最新激活码
Sep 25 #Python
PyCharm2020最新激活码+激活码补丁(亲测最新版PyCharm2020.2激活成功)
Nov 25 #Python
详解Python中第三方库Faker
Sep 25 #Python
python对批量WAV音频进行等长分割的方法实现
Sep 25 #Python
python连接mysql数据库并读取数据的实现
Sep 25 #Python
Python3如何使用tabulate打印数据
Sep 25 #Python
如何基于pandas读取csv后合并两个股票
Sep 25 #Python
You might like
php模板之Phpbean的目录结构
2008/01/10 PHP
PHP提取字符串中的图片地址[正则表达式]
2011/11/12 PHP
比较discuz和ecshop的截取字符串函数php版
2012/09/03 PHP
PHP框架Swoole定时器Timer特性分析
2014/08/19 PHP
PHP中使用php5-ffmpeg撷取视频图片实例
2015/01/07 PHP
PHP模拟登陆163邮箱发邮件及获取通讯录列表的方法
2015/03/07 PHP
PHP使用CURL实现下载文件功能示例
2019/06/03 PHP
jquery删除提示框弹出是否删除对话框
2014/01/07 Javascript
JS基于ocanvas插件实现的简单画板效果代码(附demo源码下载)
2016/04/05 Javascript
javascript实现鼠标点击页面 移动DIV
2016/12/02 Javascript
浅谈jQuery的bind和unbind事件(绑定和解绑事件)
2017/03/02 Javascript
详解angularjs的数组传参方式的简单实现
2017/07/28 Javascript
Node.js Buffer模块功能及常用方法实例分析
2019/01/05 Javascript
详解VUE单页应用骨架屏方案
2019/01/17 Javascript
TypeScript魔法堂之枚举的超实用手册
2020/10/29 Javascript
Python字符和字符值(ASCII或Unicode码值)转换方法
2015/05/21 Python
Python实现命令行通讯录实例教程
2016/08/18 Python
python检查URL是否正常访问的小技巧
2017/02/25 Python
python爬虫实战之最简单的网页爬虫教程
2017/08/13 Python
python3.6连接MySQL和表的创建与删除实例代码
2017/12/28 Python
Python实现去除列表中重复元素的方法小结【4种方法】
2018/04/27 Python
python生成多个只含0,1元素的随机数组或列表的实例
2018/11/12 Python
win7 x64系统中安装Scrapy的方法
2018/11/18 Python
Python3 log10()函数简单用法
2019/02/19 Python
Python 列表去重去除空字符的例子
2019/07/20 Python
对python中的os.getpid()和os.fork()函数详解
2019/08/08 Python
python字典的遍历3种方法详解
2019/08/10 Python
使用Tensorflow将自己的数据分割成batch训练实例
2020/01/20 Python
澳大利亚最大的百货公司:Myer
2018/12/21 全球购物
实习护士自我鉴定
2013/10/13 职场文书
专业销售业务员求职信
2013/11/18 职场文书
体育教育专业自荐信范文
2013/12/20 职场文书
css height属性中的calc方法详解
2021/06/03 HTML / CSS
Python中的程序流程控制语句
2022/02/24 Python
gtx1650怎么样 gtx1650显卡相当于什么级别
2022/04/08 数码科技
Nginx 常用配置
2022/05/15 Servers