151 lines
5.9 KiB
Python
151 lines
5.9 KiB
Python
import os
|
|
import cv2
|
|
import numpy as np
|
|
import re
|
|
from tkinter import *
|
|
from tkinter import filedialog, messagebox, colorchooser
|
|
from PIL import Image
|
|
import tkinter as tk
|
|
|
|
# 主应用类
|
|
class ImageSplitterApp:
|
|
def __init__(self, root):
|
|
self.root = root
|
|
self.root.title("图像分割工具")
|
|
self.root.geometry("500x450")
|
|
|
|
# 文件或文件夹路径
|
|
self.file_path = None
|
|
self.folder_path = None
|
|
self.selected_color = (0, 0, 0) # 默认黑色
|
|
|
|
# 创建选择文件按钮
|
|
Button(self.root, text="选择单个文件", command=self.select_file).pack(pady=10)
|
|
Button(self.root, text="选择文件夹", command=self.select_folder).pack(pady=10)
|
|
|
|
# 选择颜色按钮
|
|
Label(self.root, text="选择分割线颜色:").pack(pady=10)
|
|
Button(self.root, text="打开取色器", command=self.pick_color).pack(pady=5)
|
|
|
|
# 当前选择的颜色显示
|
|
self.color_label = Label(self.root, text=f"当前颜色: {self.selected_color}")
|
|
self.color_label.pack(pady=5)
|
|
|
|
# 命名规则
|
|
Label(self.root, text="请输入保存图片的命名规则(支持正则):").pack(pady=10)
|
|
self.naming_entry = Entry(self.root)
|
|
self.naming_entry.insert(0, r"sub_image_{idx}") # 默认命名规则
|
|
self.naming_entry.pack(pady=5)
|
|
|
|
# 分割按钮
|
|
Button(self.root, text="开始分割", command=self.split_image).pack(pady=20)
|
|
|
|
# 选择保存文件夹
|
|
self.save_folder_path = None
|
|
Button(self.root, text="选择保存文件夹", command=self.select_save_folder).pack(pady=10)
|
|
|
|
def select_file(self):
|
|
self.file_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png *.jpg *.jpeg")])
|
|
if self.file_path:
|
|
messagebox.showinfo("文件选择", f"已选择文件: {self.file_path}")
|
|
|
|
def select_folder(self):
|
|
self.folder_path = filedialog.askdirectory()
|
|
if self.folder_path:
|
|
messagebox.showinfo("文件夹选择", f"已选择文件夹: {self.folder_path}")
|
|
|
|
def select_save_folder(self):
|
|
self.save_folder_path = filedialog.askdirectory()
|
|
if self.save_folder_path:
|
|
messagebox.showinfo("保存文件夹选择", f"已选择保存文件夹: {self.save_folder_path}")
|
|
|
|
# 颜色取色器
|
|
def pick_color(self):
|
|
color = colorchooser.askcolor(title="选择分割线颜色")
|
|
if color:
|
|
self.selected_color = tuple(map(int, color[0])) # 颜色转换为整数的 (r, g, b)
|
|
self.color_label.config(text=f"当前颜色: {self.selected_color}")
|
|
|
|
# 查找分割线的位置 (通过指定颜色)
|
|
def find_dividing_lines(self, image, line_color):
|
|
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 将图像转换为灰度图
|
|
_, binary = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY_INV) # 进行二值化
|
|
|
|
# 查找水平和垂直线条
|
|
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 1))
|
|
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 25))
|
|
|
|
# 水平线
|
|
horizontal_lines = cv2.morphologyEx(binary, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
|
|
|
|
# 垂直线
|
|
vertical_lines = cv2.morphologyEx(binary, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
|
|
|
|
return horizontal_lines, vertical_lines
|
|
|
|
# 分割图像
|
|
def split_image(self):
|
|
# 提取颜色
|
|
line_color = self.selected_color
|
|
|
|
# 读取命名规则
|
|
naming_rule = self.naming_entry.get()
|
|
|
|
# 处理单个文件
|
|
if self.file_path:
|
|
self.process_file(self.file_path, line_color, naming_rule)
|
|
|
|
# 处理文件夹中的所有文件
|
|
if self.folder_path:
|
|
for file_name in os.listdir(self.folder_path):
|
|
if file_name.endswith(('.png', '.jpg', '.jpeg')):
|
|
file_path = os.path.join(self.folder_path, file_name)
|
|
self.process_file(file_path, line_color, naming_rule)
|
|
|
|
# 处理单个文件的分割
|
|
def process_file(self, file_path, line_color, naming_rule):
|
|
image = cv2.imread(file_path)
|
|
if image is None:
|
|
messagebox.showerror("错误", f"无法加载图像: {file_path}")
|
|
return
|
|
|
|
horizontal_lines, vertical_lines = self.find_dividing_lines(image, line_color)
|
|
sub_images = self.split_image_by_lines(image, horizontal_lines, vertical_lines)
|
|
|
|
# 保存分割后的图像
|
|
self.save_sub_images(sub_images, naming_rule)
|
|
|
|
# 根据分割线分割图像
|
|
def split_image_by_lines(self, image, horizontal_lines, vertical_lines):
|
|
horizontal_coords = np.where(np.any(horizontal_lines > 0, axis=1))[0]
|
|
vertical_coords = np.where(np.any(vertical_lines > 0, axis=0))[0]
|
|
|
|
sub_images = []
|
|
for i in range(len(horizontal_coords) - 1):
|
|
for j in range(len(vertical_coords) - 1):
|
|
x1, x2 = vertical_coords[j], vertical_coords[j + 1]
|
|
y1, y2 = horizontal_coords[i], horizontal_coords[i + 1]
|
|
sub_image = image[y1:y2, x1:x2]
|
|
sub_images.append(sub_image)
|
|
|
|
return sub_images
|
|
|
|
# 保存分割后的图像,支持正则命名规则
|
|
def save_sub_images(self, sub_images, naming_rule):
|
|
if not self.save_folder_path:
|
|
messagebox.showerror("错误", "请先选择保存文件夹")
|
|
return
|
|
|
|
for idx, img in enumerate(sub_images):
|
|
filename = re.sub(r'{idx}', str(idx), naming_rule) # 使用正则表达式进行命名
|
|
save_path = os.path.join(self.save_folder_path, f"{filename}.png")
|
|
cv2.imwrite(save_path, img)
|
|
|
|
messagebox.showinfo("完成", f"图像已分割并保存到 {self.save_folder_path}")
|
|
|
|
# 运行图形界面应用
|
|
if __name__ == "__main__":
|
|
root = tk.Tk()
|
|
app = ImageSplitterApp(root)
|
|
root.mainloop()
|