Files
test/gui.py
2025-07-01 17:49:48 +08:00

753 lines
30 KiB
Python

import os
import cv2
import numpy as np
from PIL import Image, ImageTk
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
import time
class WatermarkGUI:
def __init__(self, root, analyzer):
self.root = root
self.analyzer = analyzer
self.source_folder = ""
self.output_folder = ""
self.current_image = None
self.current_preview = None
self.image_files = []
self.current_index = 0
self.processing = False
self.analyzing = False
# 设置中文字体
self.font_family = "SimHei" # Windows系统默认中文字体
if os.name == "posix": # macOS/Linux
self.font_family = "WenQuanYi Micro Hei"
self.create_widgets()
def create_widgets(self):
"""创建GUI组件"""
# 主框架
main_frame = ttk.Frame(self.root, padding="20")
main_frame.pack(fill=tk.BOTH, expand=True)
# 顶部信息栏
info_frame = ttk.Frame(main_frame)
info_frame.pack(fill=tk.X, pady=(0, 10))
ttk.Label(info_frame, text="图片水印分析与去除工具 V9",
font=(self.font_family, 16, "bold")).pack(side=tk.LEFT)
# 文件夹选择区域
folder_frame = ttk.LabelFrame(main_frame, text="文件夹设置", padding="10")
folder_frame.pack(fill=tk.X, pady=10)
# 源文件夹
ttk.Label(folder_frame, text="源文件夹:", font=(self.font_family, 10)).grid(row=0, column=0, sticky=tk.W,
pady=5)
self.source_entry = ttk.Entry(folder_frame, width=60)
self.source_entry.grid(row=0, column=1, padx=5, pady=5)
ttk.Button(folder_frame, text="浏览...", command=self.browse_source_folder,
style='Accent.TButton').grid(row=0, column=2, padx=5, pady=5)
# 输出文件夹
ttk.Label(folder_frame, text="输出文件夹:", font=(self.font_family, 10)).grid(row=1, column=0, sticky=tk.W,
pady=5)
self.output_entry = ttk.Entry(folder_frame, width=60)
self.output_entry.grid(row=1, column=1, padx=5, pady=5)
ttk.Button(folder_frame, text="浏览...", command=self.browse_output_folder,
style='Accent.TButton').grid(row=1, column=2, padx=5, pady=5)
# 分析和处理区域
process_frame = ttk.Frame(main_frame)
process_frame.pack(fill=tk.X, pady=10)
# 左侧分析区域
analysis_frame = ttk.LabelFrame(process_frame, text="水印分析", padding="10")
analysis_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
self.analyze_button = ttk.Button(analysis_frame, text="分析当前图片", command=self.analyze_watermark,
style='Accent.TButton')
self.analyze_button.pack(side=tk.LEFT, padx=5, pady=5)
self.analysis_status = ttk.Label(analysis_frame, text="未分析水印",
font=(self.font_family, 10))
self.analysis_status.pack(side=tk.LEFT, padx=10, pady=5)
# 右侧处理区域
process_button_frame = ttk.LabelFrame(process_frame, text="处理", padding="10")
process_button_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
ttk.Button(process_button_frame, text="去除选中水印", command=self.process_current_image,
style='Accent.TButton').pack(side=tk.LEFT, padx=5, pady=5)
ttk.Button(process_button_frame, text="批量处理所有图片", command=self.process_all_images,
style='Accent.TButton').pack(side=tk.RIGHT, padx=5, pady=5)
# 水印选择区域
selection_frame = ttk.LabelFrame(main_frame, text="选择要去除的水印", padding="10")
selection_frame.pack(fill=tk.X, pady=10)
# 创建水印列表
columns = ("type", "x", "y", "width", "height", "confidence", "select")
self.watermark_tree = ttk.Treeview(selection_frame, columns=columns, show="headings", height=4)
# 设置列标题
self.watermark_tree.heading("type", text="类型")
self.watermark_tree.heading("x", text="X坐标")
self.watermark_tree.heading("y", text="Y坐标")
self.watermark_tree.heading("width", text="宽度")
self.watermark_tree.heading("height", text="高度")
self.watermark_tree.heading("confidence", text="置信度")
self.watermark_tree.heading("select", text="选择")
# 设置列宽
self.watermark_tree.column("type", width=80, anchor=tk.CENTER)
self.watermark_tree.column("x", width=60, anchor=tk.CENTER)
self.watermark_tree.column("y", width=60, anchor=tk.CENTER)
self.watermark_tree.column("width", width=60, anchor=tk.CENTER)
self.watermark_tree.column("height", width=60, anchor=tk.CENTER)
self.watermark_tree.column("confidence", width=80, anchor=tk.CENTER)
self.watermark_tree.column("select", width=60, anchor=tk.CENTER)
self.watermark_tree.pack(fill=tk.X, pady=5)
# 选择按钮
button_frame = ttk.Frame(selection_frame)
button_frame.pack(fill=tk.X, pady=5)
ttk.Button(button_frame, text="选择所有", command=self.select_all_watermarks).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="取消选择", command=self.deselect_all_watermarks).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="应用选择", command=self.apply_watermark_selection).pack(side=tk.RIGHT, padx=5)
# 检测参数设置
params_frame = ttk.LabelFrame(main_frame, text="检测参数设置", padding="10")
params_frame.pack(fill=tk.X, pady=10)
# 第一行参数
row1_frame = ttk.Frame(params_frame)
row1_frame.pack(fill=tk.X, pady=5)
# 文字敏感度
ttk.Label(row1_frame, text="文字敏感度:").grid(row=0, column=0, sticky=tk.W, pady=5, padx=5)
self.text_sensitivity = tk.IntVar(value=30)
text_scale = ttk.Scale(row1_frame, from_=10, to=100, orient=tk.HORIZONTAL,
variable=self.text_sensitivity, length=200, command=self.on_text_sensitivity_change)
text_scale.grid(row=0, column=1, padx=5, pady=5)
self.text_sensitivity_value = ttk.Label(row1_frame, text=str(self.text_sensitivity.get()))
self.text_sensitivity_value.grid(row=0, column=2, padx=5, pady=5)
# 印章敏感度
ttk.Label(row1_frame, text="印章敏感度:").grid(row=0, column=3, sticky=tk.W, pady=5, padx=5)
self.stamp_sensitivity = tk.IntVar(value=30)
stamp_scale = ttk.Scale(row1_frame, from_=10, to=100, orient=tk.HORIZONTAL,
variable=self.stamp_sensitivity, length=200, command=self.on_stamp_sensitivity_change)
stamp_scale.grid(row=0, column=4, padx=5, pady=5)
self.stamp_sensitivity_value = ttk.Label(row1_frame, text=str(self.stamp_sensitivity.get()))
self.stamp_sensitivity_value.grid(row=0, column=5, padx=5, pady=5)
# 第二行参数
row2_frame = ttk.Frame(params_frame)
row2_frame.pack(fill=tk.X, pady=5)
# 显著性阈值
ttk.Label(row2_frame, text="显著性阈值:").grid(row=0, column=0, sticky=tk.W, pady=5, padx=5)
self.saliency_threshold = tk.DoubleVar(value=self.analyzer.saliency_threshold)
saliency_scale = ttk.Scale(row2_frame, from_=0.1, to=0.9, orient=tk.HORIZONTAL,
variable=self.saliency_threshold, length=200,
command=lambda s: self.saliency_threshold.set(round(float(s), 1)))
saliency_scale.grid(row=0, column=1, padx=5, pady=5)
self.saliency_value = ttk.Label(row2_frame, text=str(self.saliency_threshold.get()))
self.saliency_value.grid(row=0, column=2, padx=5, pady=5)
# 边缘阈值
ttk.Label(row2_frame, text="边缘阈值:").grid(row=0, column=3, sticky=tk.W, pady=5, padx=5)
self.edge_threshold = tk.IntVar(value=self.analyzer.edge_threshold)
edge_scale = ttk.Scale(row2_frame, from_=50, to=200, orient=tk.HORIZONTAL,
variable=self.edge_threshold, length=200, command=self.on_edge_threshold_change)
edge_scale.grid(row=0, column=4, padx=5, pady=5)
self.edge_value = ttk.Label(row2_frame, text=str(self.edge_threshold.get()))
self.edge_value.grid(row=0, column=5, padx=5, pady=5)
# 第三行参数 - 检测方法选择
row3_frame = ttk.Frame(params_frame)
row3_frame.pack(fill=tk.X, pady=5)
self.use_color_filter = tk.BooleanVar(value=self.analyzer.use_color_filter)
ttk.Checkbutton(row3_frame, text="颜色过滤", variable=self.use_color_filter,
command=self.on_detection_method_change).grid(row=0, column=0, sticky=tk.W, pady=5, padx=5)
self.use_mser = tk.BooleanVar(value=self.analyzer.use_mser)
ttk.Checkbutton(row3_frame, text="文字检测(MSER)", variable=self.use_mser,
command=self.on_detection_method_change).grid(row=0, column=1, sticky=tk.W, pady=5, padx=5)
self.use_texture_analysis = tk.BooleanVar(value=self.analyzer.use_texture_analysis)
ttk.Checkbutton(row3_frame, text="纹理分析", variable=self.use_texture_analysis,
command=self.on_detection_method_change).grid(row=0, column=2, sticky=tk.W, pady=5, padx=5)
# 修复参数设置
repair_frame = ttk.LabelFrame(main_frame, text="修复参数设置", padding="10")
repair_frame.pack(fill=tk.X, pady=10)
# 第一行修复参数
repair_row1_frame = ttk.Frame(repair_frame)
repair_row1_frame.pack(fill=tk.X, pady=5)
# 修复半径
ttk.Label(repair_row1_frame, text="修复半径:").grid(row=0, column=0, sticky=tk.W, pady=5, padx=5)
self.repair_radius = tk.IntVar(value=self.analyzer.inpaint_radius)
repair_scale = ttk.Scale(repair_row1_frame, from_=1, to=15, orient=tk.HORIZONTAL,
variable=self.repair_radius, length=200, command=self.on_repair_radius_change)
repair_scale.grid(row=0, column=1, padx=5, pady=5)
self.repair_radius_value = ttk.Label(repair_row1_frame, text=str(self.repair_radius.get()))
self.repair_radius_value.grid(row=0, column=2, padx=5, pady=5)
# 修复算法
ttk.Label(repair_row1_frame, text="修复算法:").grid(row=0, column=3, sticky=tk.W, pady=5, padx=5)
self.repair_algorithm = tk.StringVar(value="TELEA")
algorithm_combo = ttk.Combobox(repair_row1_frame, textvariable=self.repair_algorithm,
values=["TELEA", "NS"], state="readonly", width=10)
algorithm_combo.grid(row=0, column=4, padx=5, pady=5)
algorithm_combo.bind("<<ComboboxSelected>>", self.on_repair_algorithm_change)
# 图像预览区域
preview_frame = ttk.LabelFrame(main_frame, text="图像预览", padding="10")
preview_frame.pack(fill=tk.BOTH, expand=True, pady=10)
# 创建画布
self.canvas_frame = ttk.Frame(preview_frame)
self.canvas_frame.pack(fill=tk.BOTH, expand=True)
self.canvas = tk.Canvas(self.canvas_frame, bg="white")
self.canvas.pack(fill=tk.BOTH, expand=True)
# 添加滚动条
self.h_scrollbar = ttk.Scrollbar(self.canvas_frame, orient=tk.HORIZONTAL, command=self.canvas.xview)
self.v_scrollbar = ttk.Scrollbar(self.canvas_frame, orient=tk.VERTICAL, command=self.canvas.yview)
self.canvas.configure(xscrollcommand=self.h_scrollbar.set, yscrollcommand=self.v_scrollbar.set)
self.h_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
self.v_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 图像导航
nav_frame = ttk.Frame(main_frame)
nav_frame.pack(fill=tk.X, pady=10)
ttk.Button(nav_frame, text="上一张", command=self.prev_image).pack(side=tk.LEFT, padx=5)
self.image_info = ttk.Label(nav_frame, text="未加载图片", font=(self.font_family, 10))
self.image_info.pack(side=tk.LEFT, padx=20)
ttk.Button(nav_frame, text="下一张", command=self.next_image).pack(side=tk.RIGHT, padx=5)
# 状态栏
self.status_bar = ttk.Label(self.root, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
# 绑定鼠标滚轮事件
self.canvas.bind("<MouseWheel>", self.on_mousewheel) # Windows
self.canvas.bind("<Button-4>", self.on_mousewheel) # Linux
self.canvas.bind("<Button-5>", self.on_mousewheel) # Linux
# 绑定画布大小变化事件
self.canvas.bind("<Configure>", self.on_canvas_configure)
def browse_source_folder(self):
"""浏览并选择源文件夹"""
folder = filedialog.askdirectory(title="选择源文件夹")
if folder:
self.source_folder = folder
self.source_entry.delete(0, tk.END)
self.source_entry.insert(0, folder)
self.load_images()
def browse_output_folder(self):
"""浏览并选择输出文件夹"""
folder = filedialog.askdirectory(title="选择输出文件夹")
if folder:
self.output_folder = folder
self.output_entry.delete(0, tk.END)
self.output_entry.insert(0, folder)
def load_images(self):
"""加载文件夹中的所有图像"""
if not self.source_folder:
return
self.image_files = []
valid_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.gif']
for file in os.listdir(self.source_folder):
if any(file.lower().endswith(ext) for ext in valid_extensions):
self.image_files.append(os.path.join(self.source_folder, file))
if self.image_files:
self.current_index = 0
self.load_current_image()
self.update_image_info()
else:
messagebox.showinfo("提示", "所选文件夹中没有找到图像文件")
def load_current_image(self):
"""加载当前选中的图像"""
if not self.image_files:
return
try:
self.current_image = cv2.imread(self.image_files[self.current_index])
if self.current_image is None:
messagebox.showerror("错误", f"无法加载图像: {self.image_files[self.current_index]}")
return
# 重置水印分析结果
self.analyzer.watermark_regions = []
self.update_watermark_tree()
self.analysis_status.config(text="未分析水印")
# 显示图像
self.display_image()
except Exception as e:
messagebox.showerror("错误", f"加载图像时出错: {str(e)}")
def display_image(self):
"""在画布上显示当前图像"""
if self.current_image is None:
return
# 复制图像用于显示
display_img = self.current_image.copy()
# 如果有选中的水印区域,在预览图上标记
for region in self.analyzer.selected_regions:
x, y, w, h = region['position']
color = (0, 255, 0) # 绿色边框
cv2.rectangle(display_img, (x, y), (x + w, y + h), color, 2)
# 转换为PIL格式
rgb_img = cv2.cvtColor(display_img, cv2.COLOR_BGR2RGB)
pil_img = Image.fromarray(rgb_img)
# 调整图像大小以适应画布
canvas_width = self.canvas.winfo_width() - 20
canvas_height = self.canvas.winfo_height() - 20
if canvas_width <= 0 or canvas_height <= 0:
return
img_width, img_height = pil_img.size
# 计算缩放比例
scale = min(canvas_width / img_width, canvas_height / img_height)
if scale < 1:
pil_img = pil_img.resize((int(img_width * scale), int(img_height * scale)), Image.LANCZOS)
# 转换为Tkinter可用的格式
self.current_preview = ImageTk.PhotoImage(image=pil_img)
# 在画布上显示图像
self.canvas.delete("all")
self.canvas.create_image(10, 10, anchor=tk.NW, image=self.current_preview)
# 更新画布滚动区域
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def update_image_info(self):
"""更新图像信息标签"""
if not self.image_files:
self.image_info.config(text="未加载图片")
return
self.image_info.config(
text=f"图片 {self.current_index + 1}/{len(self.image_files)}: {os.path.basename(self.image_files[self.current_index])}")
def prev_image(self):
"""显示上一张图片"""
if not self.image_files:
return
self.current_index = (self.current_index - 1) % len(self.image_files)
self.load_current_image()
self.update_image_info()
def next_image(self):
"""显示下一张图片"""
if not self.image_files:
return
self.current_index = (self.current_index + 1) % len(self.image_files)
self.load_current_image()
self.update_image_info()
def analyze_watermark(self):
"""分析当前图片中的水印"""
if self.current_image is None:
messagebox.showinfo("提示", "请先加载图片")
return
if self.analyzing:
messagebox.showinfo("提示", "正在进行水印分析,请稍候...")
return
# 禁用分析按钮
self.analyze_button.config(state=tk.DISABLED)
self.analysis_status.config(text="分析中...")
self.analyzing = True
# 更新分析参数
self.update_analysis_parameters()
# 在单独的线程中执行水印分析
analysis_thread = threading.Thread(target=self._analyze_watermark_thread)
analysis_thread.daemon = True
analysis_thread.start()
def _analyze_watermark_thread(self):
"""在后台线程中执行水印分析"""
try:
# 执行水印分析
start_time = time.time()
self.analyzer.analyze(self.current_image)
analysis_time = time.time() - start_time
# 更新UI
self.root.after(0, self._update_after_analysis, analysis_time)
except Exception as e:
self.root.after(0, messagebox.showerror, "错误", f"分析水印时出错: {str(e)}")
self.root.after(0, self._reset_analysis_state)
def _update_after_analysis(self, analysis_time):
"""分析完成后更新UI"""
# 更新水印列表
self.update_watermark_tree()
# 更新状态
if self.analyzer.watermark_regions:
self.analysis_status.config(
text=f"已检测到 {len(self.analyzer.watermark_regions)} 个水印区域 (耗时: {analysis_time:.2f}秒)")
else:
self.analysis_status.config(text="未检测到水印 (耗时: {analysis_time:.2f}秒)")
# 重新显示图像(包含水印标记)
self.display_image()
# 重置分析状态
self._reset_analysis_state()
def _reset_analysis_state(self):
"""重置分析状态"""
self.analyze_button.config(state=tk.NORMAL)
self.analyzing = False
def update_watermark_tree(self):
"""更新水印树状视图"""
# 清空现有项
for item in self.watermark_tree.get_children():
self.watermark_tree.delete(item)
# 添加新项
for i, region in enumerate(self.analyzer.watermark_regions):
x, y, w, h = region['position']
confidence = region['confidence']
r_type = region['type']
# 判断是否选中
is_selected = region in self.analyzer.selected_regions
select_text = "" if is_selected else ""
self.watermark_tree.insert("", tk.END, values=(
r_type, x, y, w, h, f"{confidence:.2f}", select_text
))
def select_all_watermarks(self):
"""选择所有水印区域"""
self.analyzer.selected_regions = self.analyzer.watermark_regions.copy()
self.update_watermark_tree()
self.display_image()
def deselect_all_watermarks(self):
"""取消选择所有水印区域"""
self.analyzer.selected_regions = []
self.update_watermark_tree()
self.display_image()
def apply_watermark_selection(self):
"""应用水印选择(基于用户在表格中的选择)"""
selected_regions = []
for item_id in self.watermark_tree.selection():
item = self.watermark_tree.item(item_id)
values = item['values']
if not values:
continue
# 查找对应的区域
for region in self.analyzer.watermark_regions:
x, y, w, h = region['position']
if (int(values[1]) == x and int(values[2]) == y and
int(values[3]) == w and int(values[4]) == h):
selected_regions.append(region)
break
self.analyzer.selected_regions = selected_regions
self.update_watermark_tree()
self.display_image()
def process_current_image(self):
"""处理当前图片,去除选中的水印"""
if self.current_image is None:
messagebox.showinfo("提示", "请先加载图片")
return
if not self.analyzer.selected_regions:
messagebox.showinfo("提示", "请先选择要去除的水印区域")
return
if self.processing:
messagebox.showinfo("提示", "正在处理图片,请稍候...")
return
# 更新修复参数
self.update_repair_parameters()
# 禁用处理按钮
self.processing = True
self.status_bar.config(text="处理中...")
# 在单独的线程中执行图片处理
process_thread = threading.Thread(target=self._process_current_image_thread)
process_thread.daemon = True
process_thread.start()
def _process_current_image_thread(self):
"""在后台线程中处理当前图片"""
try:
# 处理图片
result = self.analyzer.remove_watermarks(self.current_image)
# 保存结果
if self.output_folder:
output_path = os.path.join(self.output_folder,
f"processed_{os.path.basename(self.image_files[self.current_index])}")
cv2.imwrite(output_path, result)
self.status_bar.config(text=f"已保存处理后的图片: {output_path}")
else:
self.status_bar.config(text="处理完成,但未指定输出文件夹,结果未保存")
# 更新当前图片为处理后的结果
self.current_image = result
# 更新UI
self.root.after(0, self.display_image)
self.root.after(0, self._reset_processing_state)
except Exception as e:
self.root.after(0, messagebox.showerror, "错误", f"处理图片时出错: {str(e)}")
self.root.after(0, self._reset_processing_state)
def _reset_processing_state(self):
"""重置处理状态"""
self.processing = False
self.status_bar.config(text="就绪")
def process_all_images(self):
"""批量处理所有图片"""
if not self.image_files:
messagebox.showinfo("提示", "请先加载图片")
return
if not self.output_folder:
messagebox.showinfo("提示", "请先选择输出文件夹")
return
if self.processing:
messagebox.showinfo("提示", "正在处理图片,请稍候...")
return
# 更新修复参数
self.update_repair_parameters()
# 确认对话框
result = messagebox.askyesno("确认", f"确定要批量处理所有 {len(self.image_files)} 张图片吗?")
if not result:
return
total = len(self.image_files)
processed = 0
errors = 0
for i, img_path in enumerate(self.image_files):
# 更新状态栏
self.root.after(0, lambda i=i: self.status_bar.config(text=f"处理中 ({i + 1}/{total})..."))
try:
# 读取图片
img = cv2.imread(img_path)
if img is None:
errors += 1
continue
# 分析水印
self.analyzer.analyze(img)
# 处理图片
if self.analyzer.watermark_regions:
result = self.analyzer.remove_watermarks(img)
# 保存结果
output_path = os.path.join(self.output_folder,
f"processed_{os.path.basename(img_path)}")
cv2.imwrite(output_path, result)
processed += 1
except Exception as e:
print(f"处理图片 {img_path} 时出错: {str(e)}")
errors += 1
# 更新UI
self.root.after(0, lambda: messagebox.showinfo("完成",
f"批量处理完成!\n成功: {processed}\n失败: {errors}"))
self.root.after(0, lambda: self.status_bar.config(text=f"批量处理完成: 成功 {processed}, 失败 {errors}"))
self.root.after(0, self._reset_processing_state)
except Exception as e:
self.root.after(0, messagebox.showerror, "错误", f"批量处理时出错: {str(e)}")
self.root.after(0, self._reset_processing_state)
def update_analysis_parameters(self):
"""更新分析参数"""
self.analyzer.text_threshold = self.text_sensitivity.get()
self.analyzer.stamp_threshold = self.stamp_sensitivity.get()
self.analyzer.saliency_threshold = self.saliency_threshold.get()
self.analyzer.edge_threshold = self.edge_threshold.get()
self.analyzer.use_color_filter = self.use_color_filter.get()
self.analyzer.use_mser = self.use_mser.get()
self.analyzer.use_texture_analysis = self.use_texture_analysis.get()
def update_repair_parameters(self):
"""更新修复参数"""
self.analyzer.inpaint_radius = self.repair_radius.get()
if self.repair_algorithm.get() == "TELEA":
self.analyzer.inpaint_algorithm = cv2.INPAINT_TELEA
else:
self.analyzer.inpaint_algorithm = cv2.INPAINT_NS
def on_text_sensitivity_change(self, event):
"""文字敏感度滑块变化事件"""
value = self.text_sensitivity.get()
self.text_sensitivity_value.config(text=str(value))
def on_stamp_sensitivity_change(self, event):
"""印章敏感度滑块变化事件"""
value = self.stamp_sensitivity.get()
self.stamp_sensitivity_value.config(text=str(value))
def on_edge_threshold_change(self, event):
"""边缘阈值滑块变化事件"""
value = self.edge_threshold.get()
self.edge_value.config(text=str(value))
def on_repair_radius_change(self, event):
"""修复半径滑块变化事件"""
value = self.repair_radius.get()
self.repair_radius_value.config(text=str(value))
def on_repair_algorithm_change(self, event):
"""修复算法选择变化事件"""
pass
def on_detection_method_change(self):
"""检测方法选择变化事件"""
pass
def on_mousewheel(self, event):
"""鼠标滚轮事件处理"""
if event.num == 4 or event.delta > 0: # 向上滚动
self.canvas.yview_scroll(-1, "units")
elif event.num == 5 or event.delta < 0: # 向下滚动
self.canvas.yview_scroll(1, "units")
def on_canvas_configure(self, event):
"""画布大小变化事件处理"""
self.display_image()
def run_gui():
"""运行GUI应用"""
# 尝试导入Analyzer类
try:
from analyzer import WatermarkAnalyzer
analyzer = WatermarkAnalyzer()
except ImportError:
# 如果无法导入,创建一个模拟类用于演示
class WatermarkAnalyzer:
def __init__(self):
self.watermark_regions = []
self.selected_regions = []
self.inpaint_radius = 5
self.inpaint_algorithm = cv2.INPAINT_TELEA
self.text_threshold = 180
self.stamp_threshold = 180
self.saliency_threshold = 0.5
self.edge_threshold = 100
self.use_color_filter = True
self.use_mser = True
self.use_texture_analysis = True
def analyze(self, image):
# 模拟水印分析
height, width = image.shape[:2]
self.watermark_regions = [
{
'type': 'text',
'position': (width // 2 - 50, 10, 100, 30),
'confidence': 0.8,
'contour': None
},
{
'type': 'stamp',
'position': (width - 100, height - 100, 80, 80),
'confidence': 0.9,
'contour': None
}
]
self.selected_regions = self.watermark_regions.copy()
def remove_watermarks(self, image):
# 模拟水印去除
result = image.copy()
for region in self.selected_regions:
x, y, w, h = region['position']
# 创建掩码
mask = np.zeros((image.shape[0], image.shape[1]), dtype=np.uint8)
mask[y:y + h, x:x + w] = 255
# 使用修复算法去除水印
result = cv2.inpaint(result, mask, self.inpaint_radius, self.inpaint_algorithm)
return result
analyzer = WatermarkAnalyzer()
# 创建主窗口
root = tk.Tk()
root.title("图片水印分析与去除工具 V9")
root.geometry("1000x800")
# 设置样式
style = ttk.Style()
style.configure('Accent.TButton', font=(None, 10, 'bold'))
# 创建GUI
app = WatermarkGUI(root, analyzer)
# 启动主循环
root.mainloop()
if __name__ == "__main__":
run_gui()