基于Python实现网页版去复杂图片水印
Python可以用OpenCV去除图片水印,但只针对简单图片,对于复杂图片水印,目前采用最多的是固定位置去除,但是这种方式不能针对所有照片,还有就是采用AI训练的方式,就这种方式而言,效果不错,但是很耗费时间,追求完美的话,至少需要20h,从经济上讲很不划算,所以本文一种特殊的方式,通过图像转化为HSV图,提取水印照片,参考PS的方式,与原图对比稀释掉水印,这种方式有两大缺点:
(1)针对图像色彩丰富,尤其深色系效果明显;
(2)目前大部分水印为灰色较多,这种方式只针对灰色水印。
本文参考了麦拂沙博主的文章,同时转用了该文章的图片,非常感谢。
基于Flask框架实现网页上传图片
打开网页输入以下网址: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值,是否可以实现橡皮擦工具,也就是可以实现点击就能去掉水印,这个问题留待以后有时间研究一下。