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 osclass WatermarkRemoverApp:def __init__(self, root):self.root = rootself.root.title("簡單的圖片去水印工具")# 初始化變量self.original_image = Noneself.processed_image = Noneself.display_ratio = 1.0self.selection_rect = Noneself.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:returntry:self.original_image = Image.open(file_path)self.original_file_path = file_path # 保存原始路徑self.processed_image = Noneself.show_image(self.original_image)self.mask = Noneexcept 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.sizeself.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.LANCZOSelse: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_rectx1, y1 = event.x, event.yself.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_rectself.canvas.create_rectangle(x0, y0, x1, y1,outline="red",tags="selection")def remove_watermark(self):if not self.original_image:messagebox.showwarning("警告", "請先打開圖片")returnif not self.mask:messagebox.showwarning("警告", "請先選擇水印區域")returntry:# 轉換圖像格式img = cv2.cvtColor(np.array(self.original_image), cv2.COLOR_RGB2BGR)mask = np.array(self.mask)# 使用OpenCV的inpaint方法radius = 10result = 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("警告", "沒有可保存的結果")returnif 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()