基于Python開發(fā)圖片分割器
引言
在圖像處理領(lǐng)域,經(jīng)常需要將一張大圖切分成多個(gè)小圖片。本文將介紹如何使用Python開發(fā)一個(gè)帶圖形界面的圖片分割工具,并重點(diǎn)討論如何處理實(shí)際應(yīng)用中可能遇到的各種問題。這個(gè)工具允許用戶選擇圖片、設(shè)置分割的行數(shù)和列數(shù),并將分割后的圖片保存到指定目錄。
全部代碼
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('程序啟動(dòng)成功')
except Exception as e:
logging.error(f'初始化失敗: {str(e)}')
wx.MessageBox(f'程序初始化失敗: {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
self.Destroy()
def InitUI(self):
try:
# 創(chuàng)建面板
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)
# 行數(shù)和列數(shù)輸入
grid = wx.FlexGridSizer(2, 2, 5, 5)
row_label = wx.StaticText(panel, label='行數(shù):')
self.row_input = wx.SpinCtrl(panel, value='2', min=1, max=100)
col_label = wx.StaticText(panel, label='列數(shù):')
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)}', '錯(cuò)誤', 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}')
# 驗(yàn)證圖片是否可以打開
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('選擇的圖片無法打開,請(qǐng)選擇其他圖片', '錯(cuò)誤', 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'選擇圖片時(shí)發(fā)生錯(cuò)誤: {str(e)}', '錯(cuò)誤', 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}')
# 驗(yàn)證目錄寫入權(quán)限
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'目錄無寫入權(quán)限: {str(e)}')
wx.MessageBox('選擇的目錄沒有寫入權(quán)限,請(qǐng)選擇其他目錄', '錯(cuò)誤', 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'選擇保存目錄時(shí)發(fā)生錯(cuò)誤: {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
def OnSplit(self, event):
if not self.image_path:
wx.MessageBox('請(qǐng)先選擇圖片!', '提示', wx.OK | wx.ICON_INFORMATION)
return
if not self.save_dir:
wx.MessageBox('請(qǐng)選擇保存目錄!', '提示', 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}')
# 計(jì)算每個(gè)分塊的大小
rows = self.row_input.GetValue()
cols = self.col_input.GetValue()
block_width = width // cols
block_height = height // rows
logging.info(f'分割參數(shù):{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)}', '錯(cuò)誤', 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'內(nèi)存不足: {str(e)}')
wx.MessageBox('內(nèi)存不足,請(qǐng)嘗試減少分割數(shù)量或使用較小的圖片', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
except Exception as e:
logging.error(f'分割圖片失敗: {str(e)}')
wx.MessageBox(f'分割圖片時(shí)發(fā)生錯(cuò)誤: {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
def main():
try:
app = wx.App()
frame = ImageSplitterFrame()
frame.Show()
app.MainLoop()
except Exception as e:
logging.error(f'程序運(yùn)行失敗: {str(e)}')
wx.MessageBox(f'程序運(yùn)行失敗: {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
if __name__ == '__main__':
main()
技術(shù)棧選擇
本項(xiàng)目使用以下技術(shù):
- Python:主要編程語言
- wxPython:用于創(chuàng)建圖形用戶界面
- Pillow(PIL):用于圖像處理
- logging:用于日志記錄和錯(cuò)誤追蹤
基礎(chǔ)版本實(shí)現(xiàn)
1. 界面設(shè)計(jì)
首先,我們需要?jiǎng)?chuàng)建一個(gè)簡單直觀的用戶界面。主要包含以下組件:
- 選擇圖片按鈕
- 顯示圖片路徑的文本框
- 設(shè)置行數(shù)和列數(shù)的輸入框
- 選擇保存目錄的按鈕
- 執(zhí)行分割的按鈕
2. 核心功能實(shí)現(xiàn)
基礎(chǔ)版本的核心功能代碼如下:
def OnSplit(self, event):
with Image.open(self.image_path) as img:
width, height = img.size
# 計(jì)算每個(gè)分塊的大小
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)問題與優(yōu)化
在實(shí)際應(yīng)用中,我們發(fā)現(xiàn)基礎(chǔ)版本存在一些問題,主要包括:
- 程序穩(wěn)定性問題
- 錯(cuò)誤處理不完善
- 用戶反饋不足
- 內(nèi)存管理問題
1. 完善的錯(cuò)誤處理
為了提高程序的穩(wěn)定性,我們添加了全面的錯(cuò)誤處理:
try:
with Image.open(self.image_path) as img:
# 處理圖片
except MemoryError:
logging.error('內(nèi)存不足')
wx.MessageBox('內(nèi)存不足,請(qǐng)減少分割數(shù)量或使用較小的圖片')
except Exception as e:
logging.error(f'處理失敗: {str(e)}')
wx.MessageBox(f'處理圖片時(shí)發(fā)生錯(cuò)誤: {str(e)}')
2. 日志系統(tǒng)
添加日志系統(tǒng)對(duì)于追蹤和解決問題至關(guān)重要:
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. 輸入驗(yàn)證
增加了輸入驗(yàn)證來防止?jié)撛诘腻e(cuò)誤:
驗(yàn)證選擇的圖片是否可以打開
驗(yàn)證保存目錄是否有寫入權(quán)限
驗(yàn)證分割參數(shù)的合理性
4. 內(nèi)存優(yōu)化
優(yōu)化內(nèi)存使用的主要措施:
使用上下文管理器(with語句)自動(dòng)關(guān)閉文件
及時(shí)釋放不需要的資源
分塊處理大圖片
適當(dāng)?shù)漠惓L幚?/p>
最佳實(shí)踐建議
錯(cuò)誤處理
捕獲所有可能的異常
提供清晰的錯(cuò)誤信息
記錄詳細(xì)的錯(cuò)誤日志
用戶體驗(yàn)
提供清晰的操作反饋
添加進(jìn)度提示
保持界面響應(yīng)性
代碼組織
功能模塊化
清晰的注釋
良好的命名規(guī)范
文件處理
安全的文件操作
路徑合法性驗(yàn)證
權(quán)限檢查
項(xiàng)目使用說明
安裝依賴:
pip install wxPython pip install Pillow
運(yùn)行程序:
python image_splitter.py
使用步驟:
點(diǎn)擊"選擇圖片"按鈕選擇要分割的圖片
設(shè)置分割的行數(shù)和列數(shù)
選擇保存目錄
點(diǎn)擊"分割圖片"按鈕開始處理
結(jié)果如下


以上就是基于Python開發(fā)圖片分割器的詳細(xì)內(nèi)容,更多關(guān)于Python圖片分割的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用__init__.py將文件夾設(shè)置成Python模塊示例詳解
這篇文章主要為大家介紹了使用__init__.py將文件夾設(shè)置成Python模塊示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Python select及selectors模塊概念用法詳解
這篇文章主要介紹了Python select及selectors模塊概念用法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Python基礎(chǔ)globlal nonlocal和閉包函數(shù)裝飾器語法糖
這篇文章主要為大家介紹了Python基礎(chǔ)globlal nonlocal和閉包函數(shù)裝飾器語法糖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Anaconda配置pytorch-gpu虛擬環(huán)境的圖文教程
這篇文章主要介紹了Anaconda配置pytorch-gpu虛擬環(huán)境步驟整理,本文分步驟通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
Python使用random.shuffle()打亂列表順序的方法
今天小編就為大家分享一篇Python使用random.shuffle()打亂列表順序的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-11-11

