python实现简单的图片去水印工具
使用说明:
点击"打开图片"选择需要处理的图片
在图片上拖拽鼠标选择水印区域(红色矩形框)
点击"去除水印"执行处理
点击"保存结果"保存处理后的图片
运行效果
先简要说明本程序用到的python库:
(1)from PIL import Image, ImageTk, ImageDraw 和 import PIL,需要Pillow。
Pillow 是一个图像处理库,用于处理图像的打开、操作和保存。它不是 Python 标准库的一部分,是第三方库需要单独安装。
(2)import cv2,需要OpenCV。
OpenCV 是一个计算机视觉库,用于图像和视频处理、目标检测等任务。它不是 Python 标准库的一部分,是第三方库需要单独安装。
(3)import numpy as np,需要NumPy 。
NumPy 是一个科学计算库,用于高效处理多维数组和矩阵运算。它第三方库,需要单独安装。
(4)import tkinter as tk 和 from tkinter import filedialog, messagebox,需要tkinter。
tkinter 是 Python 的标准 GUI 库,用于创建图形用户界面。它是 Python 标准库的一部分,不需要单独安装。
(5)import os,需要os。
os 是 Python 的标准库,用于操作操作系统相关的功能,如文件和目录操作。它也是 Python 标准库的一部分,不需要单独安装。
Python第三方扩展库Pillow 更多情况可见 https://blog.csdn.net/cnds123/article/details/126141838
Python第三方库OpenCV (cv2) 更多情况可见 https://blog.csdn.net/cnds123/article/details/126547307
Python第三方扩展库NumPy 更多情况可见 https://blog.csdn.net/cnds123/article/details/135844660
源码如下:
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk, ImageDraw
import PIL
import cv2
import numpy as np
import os
class WatermarkRemoverApp:
def __init__(self, root):
self.root = root
self.root.title("简单的图片去水印工具")
# 初始化变量
self.original_image = None
self.processed_image = None
self.display_ratio = 1.0
self.selection_rect = None
self.mask = None
# 创建界面布局
self.create_widgets()
# 鼠标事件绑定
self.canvas.bind("<ButtonPress-1>", self.start_selection)
self.canvas.bind("<B1-Motion>", self.update_selection)
self.canvas.bind("<ButtonRelease-1>", self.end_selection)
self.original_file_path = None # 新增实例变量
def create_widgets(self):
# 工具栏
toolbar = tk.Frame(self.root)
toolbar.pack(fill=tk.X)
btn_open = tk.Button(toolbar, text="打开图片", command=self.open_image)
btn_open.pack(side=tk.LEFT, padx=2, pady=2)
btn_process = tk.Button(toolbar, text="去除水印", command=self.remove_watermark)
btn_process.pack(side=tk.LEFT, padx=2, pady=2)
btn_save = tk.Button(toolbar, text="保存结果", command=self.save_image)
btn_save.pack(side=tk.LEFT, padx=2, pady=2)
# 图像显示区域
self.canvas = tk.Canvas(self.root, bg='gray', cursor="cross")
self.canvas.pack(fill=tk.BOTH, expand=True)
def open_image(self):
file_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.jpg *.jpeg *.png *.bmp")])
if not file_path:
return
try:
self.original_image = Image.open(file_path)
self.original_file_path = file_path # 保存原始路径
self.processed_image = None
self.show_image(self.original_image)
self.mask = None
except Exception as e:
messagebox.showerror("错误", f"无法打开图片:\n{str(e)}")
def show_image(self, image):
# 计算缩放比例
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
img_width, img_height = image.size
self.display_ratio = min(
canvas_width / img_width,
canvas_height / img_height,
1.0 # 最大保持原始尺寸
)
display_size = (
int(img_width * self.display_ratio),
int(img_height * self.display_ratio)
)
# 缩放并显示图像
if hasattr(Image, 'Resampling'):
resample_method = Image.Resampling.LANCZOS
else:
resample_method = Image.LANCZOS # 旧版本回退
display_image = image.resize(display_size, resample_method)
self.tk_image = ImageTk.PhotoImage(display_image)
self.canvas.delete("all")
self.canvas.config(
width=display_size[0],
height=display_size[1]
)
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.tk_image)
def start_selection(self, event):
self.selection_rect = (event.x, event.y, event.x, event.y)
def update_selection(self, event):
if self.selection_rect:
x0, y0, _, _ = self.selection_rect
x1, y1 = event.x, event.y
self.selection_rect = (x0, y0, x1, y1)
self.draw_selection_rect()
def end_selection(self, event):
if self.selection_rect:
self.draw_selection_rect()
# 转换到原始图像坐标
x0 = int(self.selection_rect[0] / self.display_ratio)
y0 = int(self.selection_rect[1] / self.display_ratio)
x1 = int(self.selection_rect[2] / self.display_ratio)
y1 = int(self.selection_rect[3] / self.display_ratio)
# 创建掩膜
self.mask = Image.new("L", self.original_image.size, 0)
draw = ImageDraw.Draw(self.mask)
draw.rectangle([x0, y0, x1, y1], fill=255)
def draw_selection_rect(self):
self.canvas.delete("selection")
x0, y0, x1, y1 = self.selection_rect
self.canvas.create_rectangle(
x0, y0, x1, y1,
outline="red",
tags="selection"
)
def remove_watermark(self):
if not self.original_image:
messagebox.showwarning("警告", "请先打开图片")
return
if not self.mask:
messagebox.showwarning("警告", "请先选择水印区域")
return
try:
# 转换图像格式
img = cv2.cvtColor(np.array(self.original_image), cv2.COLOR_RGB2BGR)
mask = np.array(self.mask)
# 使用OpenCV的inpaint方法
radius = 10
result = cv2.inpaint(img, mask, radius, cv2.INPAINT_TELEA)
# 转换回PIL格式
self.processed_image = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
self.show_image(self.processed_image)
except Exception as e:
messagebox.showerror("错误", f"处理失败:\n{str(e)}")
def save_image(self):
if not self.processed_image:
messagebox.showwarning("警告", "没有可保存的结果")
return
if not self.original_file_path:
messagebox.showwarning("警告", "未找到原始文件信息")
return
# 生成默认文件名
original_name = os.path.basename(self.original_file_path)
default_name = f"RW_{original_name}"
file_path = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG", "*.png"), ("JPEG", "*.jpg"), ("BMP", "*.bmp")],
initialfile=default_name # 设置默认文件名
)
if file_path:
try:
self.processed_image.save(file_path)
messagebox.showinfo("成功", "图片保存成功")
except Exception as e:
messagebox.showerror("错误", f"保存失败:\n{str(e)}")
if __name__ == "__main__":
root = tk.Tk()
app = WatermarkRemoverApp(root)
root.geometry("800x600")
root.mainloop()