基于Python开发图片分割器

 更新时间:2024年12月27日 09:00:52   作者:winfredzhang  
在图像处理领域,经常需要将一张大图切分成多个小图片,本文将介绍如何使用Python开发一个带图形界面的图片分割工具,有需要的可以参考一下

引言

在图像处理领域,经常需要将一张大图切分成多个小图片。本文将介绍如何使用Python开发一个带图形界面的图片分割工具,并重点讨论如何处理实际应用中可能遇到的各种问题。这个工具允许用户选择图片、设置分割的行数和列数,并将分割后的图片保存到指定目录。

全部代码

import wx
import os
import sys
import logging
from PIL import Image
from datetime import datetime

# 配置日志
logging.basicConfig(
    filename=f'image_splitter_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log',
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class ImageSplitterFrame(wx.Frame):
    def __init__(self):
        try:
            super().__init__(parent=None, title='图片分割工具', size=(500, 400))
            self.image_path = None
            self.save_dir = None
            self.InitUI()
            logging.info('程序启动成功')
        except Exception as e:
            logging.error(f'初始化失败: {str(e)}')
            wx.MessageBox(f'程序初始化失败: {str(e)}', '错误', wx.OK | wx.ICON_ERROR)
            self.Destroy()
        
    def InitUI(self):
        try:
            # 创建面板
            panel = wx.Panel(self)
            vbox = wx.BoxSizer(wx.VERTICAL)
            
            # 选择图片按钮
            select_btn = wx.Button(panel, label='选择图片')
            select_btn.Bind(wx.EVT_BUTTON, self.OnSelect)
            vbox.Add(select_btn, 0, wx.ALL|wx.CENTER, 5)
            
            # 显示选中的图片路径
            self.path_text = wx.TextCtrl(panel, style=wx.TE_READONLY)
            vbox.Add(self.path_text, 0, wx.ALL|wx.EXPAND, 5)
            
            # 行数和列数输入
            grid = wx.FlexGridSizer(2, 2, 5, 5)
            
            row_label = wx.StaticText(panel, label='行数:')
            self.row_input = wx.SpinCtrl(panel, value='2', min=1, max=100)
            col_label = wx.StaticText(panel, label='列数:')
            self.col_input = wx.SpinCtrl(panel, value='2', min=1, max=100)
            
            grid.AddMany([
                (row_label, 0, wx.ALIGN_CENTER_VERTICAL),
                (self.row_input, 0, wx.EXPAND),
                (col_label, 0, wx.ALIGN_CENTER_VERTICAL),
                (self.col_input, 0, wx.EXPAND)
            ])
            
            vbox.Add(grid, 0, wx.ALL|wx.CENTER, 5)
            
            # 选择保存目录
            save_dir_btn = wx.Button(panel, label='选择保存目录')
            save_dir_btn.Bind(wx.EVT_BUTTON, self.OnChooseDir)
            vbox.Add(save_dir_btn, 0, wx.ALL|wx.CENTER, 5)
            
            self.dir_text = wx.TextCtrl(panel, style=wx.TE_READONLY)
            vbox.Add(self.dir_text, 0, wx.ALL|wx.EXPAND, 5)
            
            # 分割按钮
            split_btn = wx.Button(panel, label='分割图片')
            split_btn.Bind(wx.EVT_BUTTON, self.OnSplit)
            vbox.Add(split_btn, 0, wx.ALL|wx.CENTER, 5)
            
            panel.SetSizer(vbox)
            self.Centre()
            
        except Exception as e:
            logging.error(f'界面初始化失败: {str(e)}')
            wx.MessageBox(f'界面初始化失败: {str(e)}', '错误', wx.OK | wx.ICON_ERROR)
            self.Destroy()
            
    def OnSelect(self, event):
        try:
            with wx.FileDialog(self, "选择图片", wildcard="图片文件 (*.jpg;*.jpeg;*.png)|*.jpg;*.jpeg;*.png",
                             style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
                if fileDialog.ShowModal() == wx.ID_CANCEL:
                    return
                self.image_path = fileDialog.GetPath()
                logging.info(f'选择图片: {self.image_path}')
                
                # 验证图片是否可以打开
                try:
                    with Image.open(self.image_path) as img:
                        width, height = img.size
                        logging.info(f'图片大小: {width}x{height}')
                except Exception as e:
                    logging.error(f'图片无法打开: {str(e)}')
                    wx.MessageBox('选择的图片无法打开,请选择其他图片', '错误', wx.OK | wx.ICON_ERROR)
                    self.image_path = None
                    return
                
                self.path_text.SetValue(self.image_path)
                
        except Exception as e:
            logging.error(f'选择图片失败: {str(e)}')
            wx.MessageBox(f'选择图片时发生错误: {str(e)}', '错误', wx.OK | wx.ICON_ERROR)
            
    def OnChooseDir(self, event):
        try:
            with wx.DirDialog(self, "选择保存目录", style=wx.DD_DEFAULT_STYLE) as dirDialog:
                if dirDialog.ShowModal() == wx.ID_CANCEL:
                    return
                self.save_dir = dirDialog.GetPath()
                logging.info(f'选择保存目录: {self.save_dir}')
                
                # 验证目录写入权限
                test_file = os.path.join(self.save_dir, 'test.txt')
                try:
                    with open(test_file, 'w') as f:
                        f.write('test')
                    os.remove(test_file)
                except Exception as e:
                    logging.error(f'目录无写入权限: {str(e)}')
                    wx.MessageBox('选择的目录没有写入权限,请选择其他目录', '错误', wx.OK | wx.ICON_ERROR)
                    self.save_dir = None
                    return
                    
                self.dir_text.SetValue(self.save_dir)
                
        except Exception as e:
            logging.error(f'选择保存目录失败: {str(e)}')
            wx.MessageBox(f'选择保存目录时发生错误: {str(e)}', '错误', wx.OK | wx.ICON_ERROR)
    
    def OnSplit(self, event):
        if not self.image_path:
            wx.MessageBox('请先选择图片!', '提示', wx.OK | wx.ICON_INFORMATION)
            return
            
        if not self.save_dir:
            wx.MessageBox('请选择保存目录!', '提示', wx.OK | wx.ICON_INFORMATION)
            return
            
        try:
            # 打开图片
            with Image.open(self.image_path) as img:
                width, height = img.size
                logging.info(f'开始分割图片,原图大小: {width}x{height}')
                
                # 计算每个分块的大小
                rows = self.row_input.GetValue()
                cols = self.col_input.GetValue()
                
                block_width = width // cols
                block_height = height // rows
                
                logging.info(f'分割参数:{rows}行 x {cols}列,每块大小: {block_width}x{block_height}')
                
                # 分割图片
                count = 0
                for i in range(rows):
                    for j in range(cols):
                        left = j * block_width
                        upper = i * block_height
                        right = left + block_width
                        lower = upper + block_height
                        
                        # 裁剪图片
                        block = img.crop((left, upper, right, lower))
                        
                        # 保存分割后的图片
                        filename = os.path.splitext(os.path.basename(self.image_path))[0]
                        save_path = os.path.join(self.save_dir, f'{filename}_r{i+1}_c{j+1}.png')
                        
                        try:
                            block.save(save_path)
                            logging.info(f'保存分割图片: {save_path}')
                            count += 1
                        except Exception as e:
                            logging.error(f'保存分割图片失败: {str(e)}')
                            wx.MessageBox(f'保存分割图片失败: {str(e)}', '错误', wx.OK | wx.ICON_ERROR)
                            return
            
            logging.info(f'分割完成,共生成{count}张图片')
            wx.MessageBox(f'分割完成!共生成{count}张图片。', '成功', wx.OK | wx.ICON_INFORMATION)
            
        except MemoryError as e:
            logging.error(f'内存不足: {str(e)}')
            wx.MessageBox('内存不足,请尝试减少分割数量或使用较小的图片', '错误', wx.OK | wx.ICON_ERROR)
        except Exception as e:
            logging.error(f'分割图片失败: {str(e)}')
            wx.MessageBox(f'分割图片时发生错误: {str(e)}', '错误', wx.OK | wx.ICON_ERROR)

def main():
    try:
        app = wx.App()
        frame = ImageSplitterFrame()
        frame.Show()
        app.MainLoop()
    except Exception as e:
        logging.error(f'程序运行失败: {str(e)}')
        wx.MessageBox(f'程序运行失败: {str(e)}', '错误', wx.OK | wx.ICON_ERROR)

if __name__ == '__main__':
    main()

技术栈选择

本项目使用以下技术:

  • Python:主要编程语言
  • wxPython:用于创建图形用户界面
  • Pillow(PIL):用于图像处理
  • logging:用于日志记录和错误追踪

基础版本实现

1. 界面设计

首先,我们需要创建一个简单直观的用户界面。主要包含以下组件:

  • 选择图片按钮
  • 显示图片路径的文本框
  • 设置行数和列数的输入框
  • 选择保存目录的按钮
  • 执行分割的按钮

2. 核心功能实现

基础版本的核心功能代码如下:

def OnSplit(self, event):
    with Image.open(self.image_path) as img:
        width, height = img.size
        
        # 计算每个分块的大小
        rows = self.row_input.GetValue()
        cols = self.col_input.GetValue()
        
        block_width = width // cols
        block_height = height // rows
        
        # 分割图片
        for i in range(rows):
            for j in range(cols):
                left = j * block_width
                upper = i * block_height
                right = left + block_width
                lower = upper + block_height
                
                block = img.crop((left, upper, right, lower))
                save_path = os.path.join(self.save_dir, 
                    f'{filename}_r{i+1}_c{j+1}.png')
                block.save(save_path)

问题与优化

在实际应用中,我们发现基础版本存在一些问题,主要包括:

  • 程序稳定性问题
  • 错误处理不完善
  • 用户反馈不足
  • 内存管理问题

1. 完善的错误处理

为了提高程序的稳定性,我们添加了全面的错误处理:

try:
    with Image.open(self.image_path) as img:
        # 处理图片
except MemoryError:
    logging.error('内存不足')
    wx.MessageBox('内存不足,请减少分割数量或使用较小的图片')
except Exception as e:
    logging.error(f'处理失败: {str(e)}')
    wx.MessageBox(f'处理图片时发生错误: {str(e)}')

2. 日志系统

添加日志系统对于追踪和解决问题至关重要:

logging.basicConfig(
    filename=f'image_splitter_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log',
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

3. 输入验证

增加了输入验证来防止潜在的错误:

验证选择的图片是否可以打开

验证保存目录是否有写入权限

验证分割参数的合理性

4. 内存优化

优化内存使用的主要措施:

使用上下文管理器(with语句)自动关闭文件

及时释放不需要的资源

分块处理大图片

适当的异常处理

最佳实践建议

错误处理

捕获所有可能的异常

提供清晰的错误信息

记录详细的错误日志

用户体验

提供清晰的操作反馈

添加进度提示

保持界面响应性

代码组织

功能模块化

清晰的注释

良好的命名规范

文件处理

安全的文件操作

路径合法性验证

权限检查

项目使用说明

安装依赖:

pip install wxPython
pip install Pillow

运行程序:

python image_splitter.py

使用步骤:

点击"选择图片"按钮选择要分割的图片

设置分割的行数和列数

选择保存目录

点击"分割图片"按钮开始处理

结果如下

以上就是基于Python开发图片分割器的详细内容,更多关于Python图片分割的资料请关注脚本之家其它相关文章!

相关文章

  • 使用__init__.py将文件夹设置成Python模块示例详解

    使用__init__.py将文件夹设置成Python模块示例详解

    这篇文章主要为大家介绍了使用__init__.py将文件夹设置成Python模块示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Python异步爬虫多线程与线程池示例详解

    Python异步爬虫多线程与线程池示例详解

    这篇文章主要为大家介绍了Python异步爬虫多线程与线程池示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-09-09
  • Python select及selectors模块概念用法详解

    Python select及selectors模块概念用法详解

    这篇文章主要介绍了Python select及selectors模块概念用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • Python基础globlal nonlocal和闭包函数装饰器语法糖

    Python基础globlal nonlocal和闭包函数装饰器语法糖

    这篇文章主要为大家介绍了Python基础globlal nonlocal和闭包函数装饰器语法糖示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • python里大整数相乘相关技巧指南

    python里大整数相乘相关技巧指南

    对于大整数计算,一般都要用某种方法转化,否则会溢出。但是python无此担忧了。Python支持“无限精度”的整数,一般情况下不用考虑整数溢出的问题,而且Python Int类型与任意精度的Long整数类可以无缝转换,超过Int 范围的情况都将转换成Long类型。
    2014-09-09
  • Anaconda配置pytorch-gpu虚拟环境的图文教程

    Anaconda配置pytorch-gpu虚拟环境的图文教程

    这篇文章主要介绍了Anaconda配置pytorch-gpu虚拟环境步骤整理,本文分步骤通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Python使用random.shuffle()打乱列表顺序的方法

    Python使用random.shuffle()打乱列表顺序的方法

    今天小编就为大家分享一篇Python使用random.shuffle()打乱列表顺序的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11
  • 浅析python多线程中的锁

    浅析python多线程中的锁

    这篇文章主要介绍了浅析python多线程中的锁,锁由Python的threading模块提供,并且它最多被一个线程所持有,当一个线程试图获取一个已经锁在资源上的锁时,该线程通常会暂停运行,直到这个锁被释放,需要的朋友可以参考下
    2023-07-07
  • python 字符串详解

    python 字符串详解

    这篇文章主要介绍了Python的字符串,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下,希望能够给你带来帮助
    2021-10-10
  • 在Python中增加和插入元素的示例

    在Python中增加和插入元素的示例

    今天小编就为大家分享一篇在Python中增加和插入元素的示例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11

最新评论