Python可以用OpenCV去除图片水印,但只针对简单图片,对于复杂图片水印,目前采用最多的是固定位置去除,但是这种方式不能针对所有照片,还有就是采用AI训练的方式,就这种方式而言,效果不错,但是很耗费时间,追求完美的话,至少需要20h,从经济上讲很不划算,所以本文一种特殊的方式,通过图像转化为HSV图,提取水印照片,参考PS的方式,与原图对比稀释掉水印,这种方式有两大缺点:
(1)针对图像色彩丰富,尤其深色系效果明显;
(2)目前大部分水印为灰色较多,这种方式只针对灰色水印。
本文参考了麦拂沙博主的文章,同时转用了该文章的图片,非常感谢。
打开网页输入以下网址:127.0.0.1:5000,这是来源于后面代码app.run(host='0.0.0.0', port=5000, debug=True)。
水印原图
(1)Flask框架搭建
新建qushuiyin.py文件,在该文件下输入以下代码。
from flask import Flask, render_template, request, redirect, url_for, make_response, jsonify from werkzeug.utils import secure_filename import os import cv2 import time import numpy as np from PIL import Image from datetime import timedelta # 设置允许的文件格式 ALLOWED_EXTENSIONS = set(['png', 'jpg', 'JPG', 'PNG', 'bmp']) def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS app = Flask(__name__) # 设置静态文件缓存过期时间 app.send_file_max_age_default = timedelta(seconds=1) # @app.route('/upload', methods=['POST', 'GET']) @app.route('/', methods=['POST', 'GET']) # 添加路由 def upload(): if request.method == 'POST': f = request.files['file'] if not (f and allowed_file(f.filename)): return jsonify({"error": 1001, "msg": "请检查上传的图片类型,仅限于png、PNG、jpg、JPG、bmp"}) user_input = request.form.get("name") basepath = os.path.dirname(__file__) # 当前文件所在路径 upload_path = os.path.join(basepath, './static/photo', secure_filename(f.filename)) # 注意:没有的文件夹一定要先创建,不然会提示没有该路径 f.save(upload_path) return render_template('REpicture_ok.html', val1=time.time()) return render_template('REpicture.html') if __name__ == '__main__': # app.debug = True app.run(host='0.0.0.0', port=5000, debug=True)
(2)REpicture_ok.html和Repicture.html搭建
在当前目录下新建Repicture_ok.html和Repicture.html空白文件,输入以下代码。
#REpicture.html <head> <meta charset="UTF-8"> <title>图片右下角去水印</title> </head> <body> <h1>请上传图片文件</h1> <form action="" enctype='multipart/form-data' method='POST'> <input type="file" name="file" style="margin-top:20px;"/> <br> <input type="submit" value="去水印" class="button-new" style="margin-top:15px;"/> </form> </body> </html>
#REpicture_ok.html <head> <meta charset="UTF-8"> <title>图片右下角去水印</title> </head> <body> <h1>请上传图片文件</h1> <form action="" enctype='multipart/form-data' method='POST'> <input type="file" name="file" style="margin-top:20px;"/> <br> <input type="submit" value="去水印" class="button-new" style="margin-top:15px;"/> </form> <img src="{{ url_for('static', filename= './photo/result.jpg',_t=val1) }}" width="400" height="400" alt="你的图片被外星人劫持了~~"/> </body> </html>
注意:filename= './photo/result.jpg',路径要描述准确,否则会报错。
(3)得到反色水印图
原理是借鉴PS软件去水印方式,通过HSV提取出反色水印图,代码及执行结果如下:
在qushuiyin.py里f.save(upload_path)代码后接着输入以下代码:
src = cv2.imread(upload_path) rows, cols, channels = src.shape hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV) low_hsv = np.array([0, 0, 46]) high_hsv = np.array([20, 70, 200]) mask = cv2.inRange(hsv, low_hsv, high_hsv) erode = cv2.erode(mask, None, iterations=1) dilate = cv2.dilate(erode, None, iterations=1) for i in range(rows): for j in range(cols): if dilate[i, j] != 255: # 像素点255表示白色 src[i, j] = (255, 255, 255) # 此处替换颜色,为BGR通道,不是RGB通道 img = cv2.imwrite("new.png", src)
说明:
如何获取 low_hsv, high_hsv两个数组的值:
第一种方式:可以参考一下下表
第二种方式:新建一个PicNum.py的文件,输入以下代码运行(注意修改图片路径),会得到一个HSV图,鼠标左键点击你需要的地方,软件上会显示出HSV值,可以参考。
import numpy as np import cv2 src = cv2.imread("./static/3.jpg") # 用PIL中的Image.open打开图像 rows,cols,channels = src.shape hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV) def getpos(event,x,y,flags,param): if event==cv2.EVENT_LBUTTONDOWN: #定义一个鼠标左键按下去的事件 print(hsv[y,x]) cv2.imshow('imageHSV',hsv) cv2.setMouseCallback("imageHSV",getpos) cv2.waitKey(0) cv2.destroyAllWindows()
(4)实现复杂图片去水印
在上面代码的后面接着输入:
src = cv2.imread(upload_path) newImg = cv2.imread("new.png") save = np.zeros(src.shape, np.uint8) # 创建一张空图像用于保存 for row in range(src.shape[0]): for col in range(src.shape[1]): for channel in range(src.shape[2]): if newImg[row, col, channel] == 0: val = 0 else: reverse_val = 255 - src[row, col, channel] val = 255 - reverse_val * 256 / newImg[row, col, channel] if val < 0: val = 0 save[row, col, channel] = val dst = cv2.inpaint(save, mask, 3, cv2.INPAINT_TELEA) cv2.imwrite(os.path.join(basepath, './static/photo', 'result.jpg'), dst) #os.remove(os.path.join(basepath, './static/photo', 'new.png'))
给大家看看执行效果:
本文讲述的去复杂图片的水印,我觉得效果还可以,相比于通过PS软件获得反色水印图要简便快捷一些,虽然效果称不上完美,但是相比于AI训练方式也要简便快捷好多,同时还可以应用于服务器上。
最后我想留下一个问题,如果能点击获得原图的HSV值,是否可以实现橡皮擦工具,也就是可以实现点击就能去掉水印,这个问题留待以后有时间研究一下。