python opencv加水印 去水印

图片水印处理技术
本文介绍了一种基于Python的图片水印处理方法,包括水印的移除与添加。通过匹配算法定位水印并利用膨胀算法及修复算法完成水印移除,并提供了具体的实现代码示例。

python opencv加水印 去水印
python opencv加水印 去水印
收到的需求是在一个图上匹配到水印 然后将原来的水印换成一个新水印

先要安装一个库 库文件代码如下:

# coding=utf-8

import cv2
import numpy as np

# 膨胀算法 Kernel
_DILATE_KERNEL = np.array([[0, 0, 1, 0, 0],
                           [0, 0, 1, 0, 0],
                           [1, 1, 1, 1, 1],
                           [0, 0, 1, 0, 0],
                           [0, 0, 1, 0, 0]], dtype=np.uint8)

class WatermarkRemover(object):
    """"
    去除图片中的水印(Remove Watermark)
    """

    def __init__(self, verbose=True):
        self.verbose = verbose
        self.watermark_template_gray_img = None
        self.watermark_template_mask_img = None
        self.watermark_template_h = 0
        self.watermark_template_w = 0
        self.watermark_start_x = 0
        self.watermark_start_y = 0

    def load_watermark_template(self, watermark_template_filename):
        """
        加载水印模板,以便后面批量处理去除水印
        :param watermark_template_filename:
        :return:
        """
        self.generate_template_gray_and_mask(watermark_template_filename)

    def dilate(self, img):
        """
        对图片进行膨胀计算
        :param img:
        :return:
        """
        dilated = cv2.dilate(img, _DILATE_KERNEL)
        return dilated

    def generate_template_gray_and_mask(self, watermark_template_filename):
        """
        处理水印模板,生成对应的检索位图和掩码位图
        检索位图
            即处理后的灰度图,去除了非文字部分

        :param watermark_template_filename: 水印模板图片文件名称
        :return: x1, y1, x2, y2
        """

        # 水印模板原图
        img = cv2.imread(watermark_template_filename)

        # 灰度图、掩码图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        _, mask = cv2.threshold(gray, 0, 255, cv2.THRESH_TOZERO + cv2.THRESH_OTSU)
        _, mask = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)

        mask = self.dilate(mask)  # 使得掩码膨胀一圈,以免留下边缘没有被修复
        #mask = self.dilate(mask)  # 使得掩码膨胀一圈,以免留下边缘没有被修复

        # 水印模板原图去除非文字部分
        img = cv2.bitwise_and(img, img, mask=mask)

        # 后面修图时需要用到三个通道
        mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)

        self.watermark_template_gray_img = gray
        self.watermark_template_mask_img = mask

        self.watermark_template_h = img.shape[0]
        self.watermark_template_w = img.shape[1]

        # cv2.imwrite('watermark-template-gray.jpg', gray)
        # cv2.imwrite('watermark-template-mask.jpg', mask)

        return gray, mask

    def find_watermark(self, filename):
        """
        从原图中寻找水印位置
        :param filename:
        :return: x1, y1, x2, y2
        """
        # Load the images in gray scale
        gray_img = cv2.imread(filename, 0)
        return self.find_watermark_from_gray(gray_img, self.watermark_template_gray_img)

    def find_watermark_from_gray(self, gray_img, watermark_template_gray_img):
        """
        从原图的灰度图中寻找水印位置
        :param gray_img: 原图的灰度图
        :param watermark_template_gray_img: 水印模板的灰度图
        :return: x1, y1, x2, y2
        """
        # Load the images in gray scale

        method = cv2.TM_CCOEFF
        # Apply template Matching
        res = cv2.matchTemplate(gray_img, watermark_template_gray_img, method)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

        # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
        if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
            x, y = min_loc
        else:
            x, y = max_loc

        return x, y, x + self.watermark_template_w, y + self.watermark_template_h

    def remove_watermark_raw(self, img, watermark_template_gray_img, watermark_template_mask_img):
        """
        去除图片中的水印
        :param img: 待去除水印图片位图
        :param watermark_template_gray_img: 水印模板的灰度图片位图,用于确定水印位置
        :param watermark_template_mask_img: 水印模板的掩码图片位图,用于修复原始图片
        :return: 去除水印后的图片位图
        """
        # 寻找水印位置
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        x1, y1, x2, y2 = self.find_watermark_from_gray(img_gray, watermark_template_gray_img)
        self.watermark_start_x = x1
        self.watermark_start_y = y1
        # 制作原图的水印位置遮板
        mask = np.zeros(img.shape, np.uint8)
        # watermark_template_mask_img = cv2.cvtColor(watermark_template_gray_img, cv2.COLOR_GRAY2BGR)
        # mask[y1:y1 + self.watermark_template_h, x1:x1 + self.watermark_template_w] = watermark_template_mask_img
        mask[y1:y2, x1:x2] = watermark_template_mask_img
        mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)

        # 用遮板进行图片修复,使用 TELEA 算法
        dst = cv2.inpaint(img, mask, 4, cv2.INPAINT_TELEA)
        # cv2.imwrite('dst.jpg', dst)

        return dst

    def remove_watermark(self, filename, output_filename=None):
        """
        去除图片中的水印
        :param filename: 待去除水印图片文件名称
        :param output_filename: 去除水印图片后的输出文件名称
        :return: 去除水印后的图片位图
        """

        # 读取原图
        img = cv2.imread(filename)

        dst = self.remove_watermark_raw(img,
                                        self.watermark_template_gray_img,
                                        self.watermark_template_mask_img
                                        )

        if output_filename is not None:
            cv2.imwrite(output_filename, dst)

        return dst

注意 上面的代码要加上这两句 才能显示 原来水印的位置
python opencv加水印 去水印
去水印代码如下:

from nowatermark import WatermarkRemover

path = 'E:/sample/'

watermark_template_filename = path + 'watermark.png'
remover = WatermarkRemover()
remover.load_watermark_template(watermark_template_filename)

remover.remove_watermark(path + '20180516144931.png', path + '20180516144932.png')
print(remover.watermark_start_x)
print(remover.watermark_start_y)

这里输出的两个值 是指的水印在原图中的位置

加水印代码如下:

import cv2
import numpy as np
path = 'E:/sample/'
matimage = cv2.imread(path + '20180516144932.png')

#matimagenew = np.zeros((matimage.shape[0],matimage.shape[1],3))
matimagenew = matimage-matimage
watermark_template_filename = path + 'watermark.png'
matlogo = cv2.imread(watermark_template_filename)

matimagenew[359:359+matlogo.shape[0],453:453+matlogo.shape[1]] = matlogo
imagenew = cv2.addWeighted(matimage,1,matimagenew,1,1)
savepath = path + '20180516144933.png'
cv2.imwrite(savepath,imagenew)

其中的359为水印在原图中的位置的纵坐标 453为横坐标

转载于:https://blog.51cto.com/yixianwei/2117266

<think>我们被要求开发一个Python GUI程序来去除图片水印。根据引用内容,用户之前可能接触过使用Tkinter和Pillow进行图像处理(水印),现在需要去除水印去除水印通常比添水印更复杂,因为需要识别并修复水印区域。 去除水印的常见方法: 1. 基于克隆或修复的方法(如使用OpenCV的inpaint算法) 2. 基于图像分割的方法(识别水印区域,然后进行修复) 3. 如果水印是规则的(例如在固定位置、固定颜色),可以通过覆盖或颜色替换去除。 考虑到用户之前使用Tkinter和Pillow,我们可以继续使用这两个库,但为了去除水印,可能需要更强大的图像处理库,如OpenCV。 步骤: 1. 设计一个简单的GUI,允许用户选择图片,标记水印区域(或自动检测),然后去除水印并保存。 2. 由于自动检测水印可能较复杂,我们先实现让用户手动选择区域。 我们将使用: - Tkinter:用于GUI - Pillow:用于图像处理(也可以使用OpenCV,但为了与之前一致,先用Pillow,如果不行再引入OpenCV) - 对于去除水印,简单的做法是:如果水印是纯色(比如白色),我们可以用周围像素的平均值来替换。但更通用的方法是使用修复算法。 然而,Pillow本身没有提供图像修复功能,因此我们需要使用OpenCV的inpaint方法。所以,我们将同时使用Pillow和OpenCV,并在它们之间转换图像。 安装所需库(用户可能需要安装): ```bash pip install pillow opencv-python numpy ``` 设计思路: 1. 创建一个Tkinter窗口,包含一个按钮用于打开图片。 2. 显示图片,并允许用户通过鼠标拖动选择水印区域(矩形)。 3. 用户选择区域后,点击“去除水印”按钮。 4. 使用OpenCV的inpaint函数修复选定的区域。 注意:inpaint需要一张掩码图像(mask),其中水印区域为白色,其他区域为黑色。 实现步骤: - 打开图片后,显示在Canvas上。 - 用户用鼠标在图片上选择矩形区域(记录矩形左上角和右下角坐标)。 - 根据矩形区域生成一个掩码图像(矩形内部为白色,其余为黑色)。 - 将原图转换为OpenCV格式(BGR),然后使用inpaint函数。 - 将修复后的图像转换回Pillow格式并显示。 由于Tkinter的Canvas支持鼠标事件,我们可以用它来绘制矩形选择框。 代码结构: 1. 导入必要的库。 2. 创建主窗口。 3. 定义全局变量存储图像、选择区域的坐标和图像显示相关变量。 4. 定义打开图片的函数。 5. 定义鼠标事件处理函数:按下、拖动、释放。 6. 在Canvas上绘制矩形选择框。 7. 定义去除水印的函数:根据选择的区域生成掩码,调用inpaint。 8. 显示修复后的图像。 注意:inpaint有两种算法:INPAINT_TELEA(快速)和INPAINT_NS(质量更好)。我们选择TELEA。 由于去除水印的效果取决于选择的区域和原始图像,可能不会完美,但这是基本方法。 下面我们开始编写代码。由于代码较长,我们将分步骤编写。</think>### Python GUI 图像处理工具 - 去除水印实现教程 我将为您设计一个基于Python的图形界面程序,用于去除图片上的水印。这个方案结合了Tkinter(GUI界面)和OpenCV(图像处理)库,实现高效的水印去除功能。 #### 核心实现原理 水印去除主要使用**图像修复技术**(inpainting),其数学原理可表示为: $$I_{\text{修复}}(x,y) = \arg\min_I \int_\Omega |\nabla I - \nabla I_0|^2 dxdy$$ 其中$I_0$是原始图像,$\Omega$是水印区域[^1]。OpenCV提供了两种实现算法: 1. **Navier-Stokes算法**(基于流体动力学) 2. **快速行进算法**(基于快速行进方法) #### 完整实现代码 ```python import tkinter as tk from tkinter import filedialog, messagebox, ttk import cv2 import numpy as np from PIL import Image, ImageTk class WatermarkRemover: def __init__(self, root): self.root = root self.root.title("图片水印去除工具") self.root.geometry("1000x700") # 创建界面组件 self.create_widgets() # 初始化变量 self.image = None self.original_image = None self.mask = None self.rect_coords = None self.drawing = False def create_widgets(self): # 左侧控制面板 control_frame = ttk.LabelFrame(self.root, text="操作面板", padding=10) control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10) # 按钮组 ttk.Button(control_frame, text="打开图片", command=self.open_image).pack(pady=5, fill=tk.X) ttk.Button(control_frame, text="选择水印区域", command=self.start_selection).pack(pady=5, fill=tk.X) ttk.Button(control_frame, text="去除水印", command=self.remove_watermark).pack(pady=5, fill=tk.X) ttk.Button(control_frame, text="保存结果", command=self.save_image).pack(pady=5, fill=tk.X) # 算法选择 ttk.Label(control_frame, text="修复算法:").pack(pady=(15,5), anchor=tk.W) self.algorithm = tk.StringVar(value="telea") ttk.Radiobutton(control_frame, text="快速行进法", variable=self.algorithm, value="telea").pack(anchor=tk.W) ttk.Radiobutton(control_frame, text="Navier-Stokes", variable=self.algorithm, value="ns").pack(anchor=tk.W) # 参数设置 ttk.Label(control_frame, text="修复半径:").pack(pady=(15,5), anchor=tk.W) self.radius = tk.IntVar(value=3) ttk.Scale(control_frame, from_=1, to=20, variable=self.radius, orient=tk.HORIZONTAL, length=180).pack(anchor=tk.W) # 图像显示区域 image_frame = ttk.Frame(self.root) image_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10) self.canvas = tk.Canvas(image_frame, bg='#f0f0f0') self.canvas.pack(fill=tk.BOTH, expand=True) self.canvas.bind("<Button-1>", self.start_rect) self.canvas.bind("<B1-Motion>", self.draw_rect) self.canvas.bind("<ButtonRelease-1>", self.end_rect) def open_image(self): file_path = filedialog.askopenfilename(filetypes=[("图片文件", "*.jpg *.jpeg *.png *.bmp")]) if not file_path: return self.image = cv2.imread(file_path) self.original_image = self.image.copy() self.mask = None self.display_image(self.image) def display_image(self, image): self.canvas.delete("all") image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) pil_image = Image.fromarray(image) # 缩放图像以适应画布 canvas_width = self.canvas.winfo_width() - 20 canvas_height = self.canvas.winfo_height() - 20 if pil_image.width > canvas_width or pil_image.height > canvas_height: ratio = min(canvas_width/pil_image.width, canvas_height/pil_image.height) new_size = (int(pil_image.width * ratio), int(pil_image.height * ratio)) pil_image = pil_image.resize(new_size, Image.LANCZOS) self.tk_image = ImageTk.PhotoImage(pil_image) self.canvas.create_image(10, 10, anchor=tk.NW, image=self.tk_image) def start_selection(self): if self.image is None: messagebox.showerror("错误", "请先打开图片!") return self.drawing = True self.rect_coords = None messagebox.showinfo("提示", "请在图片上拖动鼠标选择水印区域") def start_rect(self, event): if self.drawing: self.rect_start = (event.x, event.y) self.rect_id = self.canvas.create_rectangle( event.x, event.y, event.x, event.y, outline="red", width=2) def draw_rect(self, event): if self.drawing and hasattr(self, 'rect_id'): self.canvas.coords(self.rect_id, self.rect_start[0], self.rect_start[1], event.x, event.y) def end_rect(self, event): if self.drawing and hasattr(self, 'rect_id'): self.rect_coords = (self.rect_start[0], self.rect_start[1], event.x, event.y) self.drawing = False def remove_watermark(self): if self.image is None: messagebox.showerror("错误", "请先打开图片!") return if self.rect_coords is None: messagebox.showerror("错误", "请先选择水印区域!") return # 创建掩码 self.mask = np.zeros(self.image.shape[:2], dtype=np.uint8) x1, y1, x2, y2 = self.rect_coords # 调整坐标到原始图像尺寸 scale_x = self.image.shape[1] / self.canvas.winfo_width() scale_y = self.image.shape[0] / self.canvas.winfo_height() x1, x2 = int(x1 * scale_x), int(x2 * scale_x) y1, y2 = int(y1 * scale_y), int(y2 * scale_y) # 确保坐标在图像范围内 x1, x2 = max(0, min(x1, x2)), min(self.image.shape[1], max(x1, x2)) y1, y2 = max(0, min(y1, y2)), min(self.image.shape[0], max(y1, y2)) self.mask[y1:y2, x1:x2] = 255 # 选择修复算法 algorithm = cv2.INPAINT_TELEA if self.algorithm.get() == "telea" else cv2.INPAINT_NS # 执行修复 self.image = cv2.inpaint(self.image, self.mask, self.radius.get(), algorithm) # 显示结果 self.display_image(self.image) messagebox.showinfo("完成", "水印去除!") def save_image(self): if self.image is None: messagebox.showerror("错误", "没有图像可保存!") return file_path = filedialog.asksaveasfilename( defaultextension=".png", filetypes=[("PNG文件", "*.png"), ("JPEG文件", "*.jpg"), ("所有文件", "*.*")]) if file_path: cv2.imwrite(file_path, self.image) messagebox.showinfo("保存成功", f"图片已保存至:\n{file_path}") if __name__ == "__main__": root = tk.Tk() app = WatermarkRemover(root) root.mainloop() ``` #### 功能说明 1. **打开图片**:支持常见格式(JPG/PNG/BMP) 2. **水印区域选择**:通过鼠标拖动矩形选择水印区域 3. **修复算法选择**: - 快速行进法(Telea):速度较快 - Navier-Stokes:质量较高 4. **参数调节**:可调整修复半径(影响修复区域大小) 5. **结果保存**:支持PNG/JPEG格式保存 #### 技术要点 1. **图像修复算法**:使用OpenCV的`inpaint`函数 2. **坐标转换**:处理Canvas坐标与原始图像坐标的映射关系 3. **交互体验**:实时矩形绘制,操作反馈 4. **图像显示优化**:自动缩放适应窗口大小 #### 使用说明 1. 安装依赖库:`pip install opencv-python pillow numpy` 2. 运行程序后,点击"打开图片"选择图像 3. 点击"选择水印区域",在图像上拖动鼠标选择水印区域 4. 选择修复算法和参数 5. 点击"去除水印"执行修复 6. 满意后点击"保存结果"导出图片 #### 效果优化建议 1. 对于半透明水印:可尝试颜色通道分离处理 2. 复杂背景水印:结合边缘检测算法优化掩码 3. 大型水印:分块处理避免失真 4. 彩色水印:使用HSV颜色空间处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值