图像九宫格切分1x3、3x3 Python


1、需求

  • 把一个图像切分成 1x3 或者 3x3
  • 切分出来的图像比例希望都是 1:1 正方形
  • 如果图像尺寸满足 切分条件,自动填充一些“白边”然后继续切分
  • 如果填充了白边的话,希望能够调整原图像在画布上的位置(居中、对齐左边等)
  • 都到这了,或许可以给原图像再加一个边距,这样如果刚好够切分图像整体也会多一层“白边”

2、实现

2-1 贴图、切分

秉持着怎么方便怎么来的原则,就用一下 Pillow 库。

1、打开图像获取尺寸,计算画布大小
Image.open Image.size
2、创建新画布,并将目标贴进去
Image.new Image.paste
3、对贴好图的画布进行切分
Image.crop Image.save

2-2 GUI

界面不是很复杂,也不需要很复杂,那就用 tkinter

1、图片路径、输出路径
tkinter.filedialog tkinter.Label tkinter.Entry tkinter.Button
2、切分模式、对齐模式
tkinter.Label tkinter.Button
3、背景颜色
tkinter.Label tkinter.colorchooser.askcolor tkinter.Button
4、内边距
tkinter.Label tkinter.Scale

3、运行效果

分析结束,走你
在这里插入图片描述
3x3切分
1x3切分

4、代码

from typing import Union
from PIL import Image
from os.path import exists, split as path_split
from os import makedirs


class ImgAlign:
    START = 0
    CENTER = 1
    END = 2

    MIDDLE = (CENTER, CENTER)
    LEFT_CENTER = (START, CENTER)
    RIGHT_CENTER = (END, CENTER)

    LEFT_TOP = (START, START)
    CENTER_TOP = (CENTER, START)
    RIGHT_TOP = (END, START)

    LEFT_BOTTOM = (START, END)
    CENTER_BOTTOM = (CENTER, END)
    RIGHT_BOTTOM = (END, END)

    ALIGNS = [
            LEFT_TOP, CENTER_TOP, RIGHT_TOP,
            LEFT_CENTER, MIDDLE, RIGHT_CENTER,
            LEFT_BOTTOM, CENTER_BOTTOM, RIGHT_BOTTOM
        ]

    def __getitem__(self, item: int):
        return self.ALIGNS[item]


class ImgSpliter:
    ONELINE_MODE = 1
    THREELINE_MODE = 0
    WHITE = '#FFF'
    BLACK = '#000'
    PADDING = Union[int,
                    list[int, int], tuple[int, int],
                    list[int, int, int, int], tuple[int, int, int, int]]

    def __init__(self):
        self.id = 0

    @classmethod
    def split_it(cls, img_path: str, out_dir='./', save_origin=False, mode=ONELINE_MODE,
                 bg=WHITE, padding: PADDING = (0, 0), align=ImgAlign.MIDDLE):
        """
        切分图像
        :param img_path: 图像路径
        :param out_dir: 切分后图像保存文件夹
        :param mode: 切分模式:一行还是三行
        :param bg: 画布背景颜色。Image.new 里的color配置
        :param padding: 画布内边距(相当于原图像外边距)。可以是 n(上下左右都是n);(上下,左右) ;(上,下,下,左,右)
        :param align: 对齐方式。 ImgAlign 里的”枚举“
        :return:
        """
        _padding = (0, 0, 0, 0)
        if isinstance(padding, int):
            _padding = (padding, padding, padding, padding)
        elif isinstance(padding, (tuple, list)):
            if len(padding) == 2:
                _padding = (padding[0], padding[0], padding[1], padding[1])
            elif len(padding) == 4:
                _padding = padding
                pass
            else:
                raise ValueError("padding 数组长度应为2或者4")
        else:
            raise ValueError("padding 数组长度应为2或者4")
        im = Image.open(img_path)
        img_name = '.'.join(path_split(img_path)[-1].split('.')[:-1])
        _out_dir = out_dir + f'/{img_name}'
        img_format = im.format
        width, height = im.size
        width += _padding[2] + _padding[3]
        height += _padding[0] + _padding[1]
        if not exists(_out_dir):
            makedirs(_out_dir)
        if mode == cls.ONELINE_MODE:
            # 1、宽小于等于三倍高。总长三倍高
            if width <= height*3:
                bk_size = (height*3, height)
            # 2、宽大于三倍高。总长等于宽,总高等于三分之一长。
            else:
                fix_width = width % 3
                _width = width + (3-fix_width if fix_width else 0)
                bk_size = (_width, _width // 3)
            paste_start_x = 0  # START
            if align[0] == ImgAlign.CENTER:
                paste_start_x = (bk_size[0]-width)//2
            elif align[0] == ImgAlign.END:
                paste_start_x = bk_size[0]-width
            paste_start_y = 0  # START
            if align[1] == ImgAlign.CENTER:
                paste_start_y = (bk_size[1]-height)//2
            elif align[1] == ImgAlign.END:
                paste_start_y = bk_size[1] - height
            bk = Image.new('RGB', bk_size, bg)
            bk.paste(im, (paste_start_x+_padding[2], paste_start_y+_padding[0]))
            if save_origin:
                tail = 1
                origin_out_path = f'{_out_dir}/{img_name}_wrap.{img_format}'
                while exists(origin_out_path):
                    origin_out_path = f'{_out_dir}/{img_name}_wrap-{tail}.{img_format}'
                    tail += 1
                bk.save(origin_out_path)
            im.close()
            for i in range(3):
                curr_img = bk.crop((
                    i*bk_size[1],
                    0,
                    (i+1) * bk_size[1],
                    bk_size[1]
                ))
                tail = 1
                out_path = f'{_out_dir}/{img_name}_{i+1}.{img_format}'
                while exists(out_path):
                    out_path = f'{_out_dir}/{img_name}_{i+1}-{tail}.{img_format}'
                    tail += 1
                curr_img.save(out_path)
                curr_img.close()
                yield i+1, out_path
            bk.close()
        elif mode == cls.THREELINE_MODE:
            _canvas_size = max(width, height)
            fix_size = 3 - _canvas_size % 3 if _canvas_size % 3 else 0
            canvas_size = _canvas_size + fix_size
            per_size = canvas_size // 3

            paste_start_x = 0  # START
            if align[0] == ImgAlign.CENTER:
                paste_start_x = (canvas_size-width)//2
            elif align[0] == ImgAlign.END:
                paste_start_x = canvas_size-width
            paste_start_y = 0  # START
            if align[1] == ImgAlign.CENTER:
                paste_start_y = (canvas_size-height)//2
            elif align[1] == ImgAlign.END:
                paste_start_y = canvas_size - height

            bk = Image.new('RGB', (canvas_size, canvas_size), bg)
            bk.paste(im, (paste_start_x+_padding[2], paste_start_y+_padding[0]))
            if save_origin:
                tail = 1
                origin_out_path = f'{_out_dir}/{img_name}_wrap.{img_format}'
                while exists(origin_out_path):
                    origin_out_path = f'{_out_dir}/{img_name}_wrap-{tail}.{img_format}'
                    tail += 1
                bk.save(origin_out_path)
            im.close()
            for row in range(3):
                for col in range(3):
                    x_start = col * per_size
                    y_start = row * per_size
                    curr_img = bk.crop((
                        x_start, y_start,
                        x_start + per_size, y_start + per_size
                    ))
                    tail = 1
                    out_path = f'{_out_dir}/{img_name}_{row + 1}{col + 1}.{img_format}'
                    while exists(out_path):
                        out_path = f'{_out_dir}/{img_name}_{row + 1}{col + 1}-{tail}.{img_format}'
                        tail += 1
                    curr_img.save(out_path)
                    curr_img.close()
                    yield row*3+col+1, out_path
            bk.close()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的壳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值