如何使用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中将阿拉伯数字转换成中文的实现代码
May 19 Python
python将人民币转换大写的脚本代码
Feb 10 Python
Python中用altzone()方法处理时区的教程
May 22 Python
浅谈Python基础之I/O模型
May 11 Python
python的多重继承的理解
Aug 06 Python
Python 实现两个列表里元素对应相乘的方法
Nov 14 Python
Python 利用切片从列表中取出一部分使用的方法
Feb 01 Python
python中的单引号双引号区别知识点总结
Jun 23 Python
Flask和pyecharts实现动态数据可视化
Feb 26 Python
Python小白学习爬虫常用请求报头
Jun 03 Python
如何使用Python实现一个简易的ORM模型
May 12 Python
如何在Python中妥善使用进度条详解
Apr 05 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生成等比缩略图类和自定义函数分享
2014/06/25 PHP
Laravel最佳分割路由文件(routes.php)的方式
2016/08/04 PHP
PHP工厂模式简单实现方法示例
2018/05/23 PHP
laravel7学习之无限级分类的最新实现方法
2020/09/30 PHP
jquery 操作单选框,复选框,下拉列表实现代码
2009/10/27 Javascript
JSON 学习之JSON in JavaScript详细使用说明
2010/02/23 Javascript
30分钟就入门的正则表达式基础教程
2013/02/25 Javascript
nodejs获取本机内网和外网ip地址的实现代码
2014/06/01 NodeJs
JavaScript学习笔记之Function对象
2015/01/22 Javascript
限制上传文件大小和格式的jQuery插件实例
2015/01/24 Javascript
Javascript进制转换实例分析
2015/05/14 Javascript
javascript日期比较方法实例分析
2016/06/17 Javascript
Angular6 Filter实现页面搜索的示例代码
2018/12/02 Javascript
基于Vue中的父子传值问题解决
2020/07/27 Javascript
解决vue项目获取dom元素宽高总是不准确问题
2020/07/29 Javascript
浅析JavaScript 函数柯里化
2020/09/08 Javascript
vue 手机物理监听键+退出提示代码
2020/09/09 Javascript
微信小程序之高德地图多点路线规划过程示例详解
2021/01/18 Javascript
opencv python统计及绘制直方图的方法
2019/01/21 Python
python保存字典和读取字典的实例代码
2019/07/07 Python
Python函数的定义方式与函数参数问题实例分析
2019/12/26 Python
如何通过python实现人脸识别验证
2020/01/17 Python
Tensorflow 实现释放内存
2020/02/03 Python
Nginx+Uwsgi+Django 项目部署到服务器的思路详解
2020/05/08 Python
Python调用C/C++的方法解析
2020/08/05 Python
html5 touch事件实现页面上下滑动效果【附代码】
2016/03/10 HTML / CSS
HTML5注册表单的自动聚焦与占位文本示例代码
2013/07/19 HTML / CSS
eDreams意大利:南欧领先的在线旅行社
2018/11/23 全球购物
材料加工硕士生求职信
2013/10/10 职场文书
传播学专业毕业生自荐信
2013/11/04 职场文书
2014年综合治理工作总结
2014/11/20 职场文书
2014年图书室工作总结
2014/12/09 职场文书
社区义诊通知
2015/04/24 职场文书
2015年教师见习期工作总结
2015/05/20 职场文书
政审证明范文
2015/06/19 职场文书
2016年教师学习廉政准则心得体会
2016/01/20 职场文书