Python去除图片水印实现方法详解

  • Post category:Python

Python去除图片水印实现方法详解

什么是图片水印

图片水印是指在图片上添加一些透明的文字或图形等信息,用于防止图片被盗用或侵权。通常情况下,图片水印是不影响图片整体的美观和观感的,但在某些情况下,图片水印却成了一个麻烦的问题,比如用于识别某个公司的某个品牌,或者一些恶意水印侵犯了用户的隐私,这时我们就需要用代码的方式对图片进行去除水印处理。

Python去除图片水印的实现方法

预处理

图片是由像素点组成的,可以通过像素点的rgb值来识别水印图片。我们可以通过安装Pillow库来对图片进行预处理,用以下代码读取图片:

from PIL import Image

img = Image.open('image.jpg').convert('RGBA')

识别水印位置

一旦我们得到了图片的rgba值,我们可以通过对比图像各个区域颜色的变化,找到水印的位置。一个简单的方法是对图片进行高斯模糊处理,然后和原图进行对比,得到一个掩码,从而识别出水印的位置。

import cv2
import numpy as np

img = cv2.imread('image.jpg')

# 高斯模糊处理
img_blur = cv2.GaussianBlur(img, (25,25), 0)

# 对比原图得到掩码
img_diff = cv2.absdiff(img, img_blur)
mask = cv2.cvtColor(img_diff, cv2.COLOR_BGR2GRAY)
_, mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

去除水印

有了水印的位置信息,我们可以通过修改像素的rgb值,来达到去除水印的效果。在去除水印时,我们可以通过以下两种方法:

方法一:用图片中不包含水印的区域来填充水印位置

for y in range(img.shape[0]):
    for x in range(img.shape[1]):
        if mask[y][x] != 0:
            img[y][x] = [0,0,0,0]

img_blur2 = cv2.GaussianBlur(img, (25,25), 0)
img = np.where(np.expand_dims(mask, axis=-1) == 255, img_blur2, img)

方法二:用邻近像素来填充水印位置

for y in range(img.shape[0]):
    for x in range(img.shape[1]):
        if mask[y][x] != 0:
            if y - 1 >= 0 and mask[y - 1][x] == 0:
                img[y][x] = img[y - 1][x]
            elif y + 1 < img.shape[0] and mask[y + 1][x] == 0:
                img[y][x] = img[y + 1][x]
            elif x - 1 >= 0 and mask[y][x - 1] == 0:
                img[y][x] = img[y][x - 1]
            elif x + 1 < img.shape[1] and mask[y][x + 1] == 0:
                img[y][x] = img[y][x + 1]

img = cv2.GaussianBlur(img, (25,25), 0)

示例说明

示例一:去除单个图片的水印

from PIL import Image
import cv2
import numpy as np

# 读取图片
img = Image.open('image.jpg').convert('RGBA')
img.save('image.png')
img = cv2.imread('image.png')

# 高斯模糊处理
img_blur = cv2.GaussianBlur(img, (25,25), 0)

# 对比原图得到掩码
img_diff = cv2.absdiff(img, img_blur)
mask = cv2.cvtColor(img_diff, cv2.COLOR_BGR2GRAY)
_, mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# 用邻近像素来填充水印位置
for y in range(img.shape[0]):
    for x in range(img.shape[1]):
        if mask[y][x] != 0:
            if y - 1 >= 0 and mask[y - 1][x] == 0:
                img[y][x] = img[y - 1][x]
            elif y + 1 < img.shape[0] and mask[y + 1][x] == 0:
                img[y][x] = img[y + 1][x]
            elif x - 1 >= 0 and mask[y][x - 1] == 0:
                img[y][x] = img[y][x - 1]
            elif x + 1 < img.shape[1] and mask[y][x + 1] == 0:
                img[y][x] = img[y][x + 1]

img = cv2.GaussianBlur(img, (25,25), 0)
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
img.save('image_without_watermark.jpg')

示例二:批量去除图片水印

import os
from PIL import Image
import cv2
import numpy as np

# 获取指定路径下所有jpg图片列表
def get_img_list(dir_path):
    img_list = []
    for filename in os.listdir(dir_path):
        if filename.endswith('.jpg'):
            img_list.append(os.path.join(dir_path, filename))
    return img_list

# 批量去除水印并保存
def batch_remove_watermark(img_list):
    for img_path in img_list:
        img = Image.open(img_path).convert('RGBA')
        img.save('temp.png')
        img = cv2.imread('temp.png')

        # 高斯模糊处理
        img_blur = cv2.GaussianBlur(img, (25,25), 0)

        # 对比原图得到掩码
        img_diff = cv2.absdiff(img, img_blur)
        mask = cv2.cvtColor(img_diff, cv2.COLOR_BGR2GRAY)
        _, mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

        # 用邻近像素来填充水印位置
        for y in range(img.shape[0]):
            for x in range(img.shape[1]):
                if mask[y][x] != 0:
                    if y - 1 >= 0 and mask[y - 1][x] == 0:
                        img[y][x] = img[y - 1][x]
                    elif y + 1 < img.shape[0] and mask[y + 1][x] == 0:
                        img[y][x] = img[y + 1][x]
                    elif x - 1 >= 0 and mask[y][x - 1] == 0:
                        img[y][x] = img[y][x - 1]
                    elif x + 1 < img.shape[1] and mask[y][x + 1] == 0:
                        img[y][x] = img[y][x + 1]

        img = cv2.GaussianBlur(img, (25,25), 0)
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        img.save(os.path.join('output', os.path.basename(img_path)))
    os.remove('temp.png')

# 测试
img_list = get_img_list('input')
if not os.path.exists('output'):
    os.makedirs('output')
batch_remove_watermark(img_list)