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

发布时间:2023年12月25日


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

文章来源:https://blog.csdn.net/qq_45020818/article/details/135207241
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。