如何使用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实现提取谷歌音乐搜索结果的方法
Jul 10 Python
Python多进程同步简单实现代码
Apr 27 Python
python reduce 函数使用详解
Dec 05 Python
python3模拟实现xshell远程执行liunx命令的方法
Jul 12 Python
Python 限定函数参数的类型及默认值方式
Dec 24 Python
Python Flask上下文管理机制实例解析
Mar 16 Python
Python通过socketserver处理多个链接
Mar 18 Python
Pandas将列表(List)转换为数据框(Dataframe)
Apr 24 Python
Python3读取和写入excel表格数据的示例代码
Jun 09 Python
Python中openpyxl实现vlookup函数的实例
Oct 28 Python
如何用Django处理gzip数据流
Jan 29 Python
Python开发工具Pycharm的安装以及使用步骤总结
Jun 24 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解密Unicode及Escape加密字符串
2015/05/17 PHP
php微信开发之批量生成带参数的二维码
2016/06/26 PHP
PHP基于自定义函数实现的汉字转拼音功能实例
2017/09/30 PHP
PHP实现本地图片转base64格式并上传
2020/05/29 PHP
firefox浏览器下javascript 拖动层效果与原理分析代码
2007/12/04 Javascript
jquery显示隐藏input对象
2014/07/21 Javascript
javascript实现仿IE顶部的可关闭警告条
2015/05/05 Javascript
JavaScript数组各种常见用法实例分析
2015/08/04 Javascript
多种JQuery循环滚动文字图片效果代码
2020/06/23 Javascript
Angular.js指令学习中一些重要属性的用法教程
2017/05/24 Javascript
详解Vue路由开启keep-alive时的注意点
2017/06/20 Javascript
nodejs模块学习之connect解析
2017/07/05 NodeJs
JS关于刷新页面的相关总结
2018/05/09 Javascript
JS实现生成由字母与数字组合的随机字符串功能详解
2018/05/25 Javascript
vue iview的菜单组件Mune 点击不高亮的解决方案
2019/11/01 Javascript
JS实现滑动插件
2020/01/15 Javascript
vue监听滚动事件的方法
2020/12/21 Vue.js
[01:35]2014DOTA2西雅图邀请赛 专访狐狸妈青春献给刀塔
2014/07/08 DOTA
[44:43]完美世界DOTA2联赛决赛日 FTD vs GXR 第一场 11.08
2020/11/11 DOTA
python中使用smtplib和email模块发送邮件实例
2014/04/22 Python
python脚本内运行linux命令的方法
2015/07/02 Python
基于Python3 逗号代码 和 字符图网格(详谈)
2017/06/22 Python
浅谈Python黑帽子取代netcat
2018/02/10 Python
python交易记录链的实现过程详解
2019/07/03 Python
详解python播放音频的三种方法
2019/09/23 Python
Python 单例设计模式用法实例分析
2019/09/23 Python
基于python读取.mat文件并取出信息
2019/12/16 Python
Python tornado上传文件的功能
2020/03/26 Python
Under Armour安德玛法国官网:美国高端运动科技品牌
2018/06/29 全球购物
年会搞笑主持词串词
2014/03/24 职场文书
抗洪救灾先进集体事迹材料
2014/05/26 职场文书
2014年感恩母亲演讲稿
2014/05/27 职场文书
承诺书范本
2015/01/21 职场文书
少先大队干部竞选稿
2015/11/20 职场文书
2019个人工作计划书的格式及范文!
2019/07/04 职场文书
CentOS7环境下MySQL8常用命令小结
2022/06/10 Servers