引言
本文主要基于cv2.inpaint函数实现图片的水印去除。
inpaint函数基于图像修复算法,通过对缺陷区域周围像素的分析和插值,生成合适的像素值来填充缺陷区域。这种算法通常用于去除图像中的污点、划痕或其他不需要的对象。
inpaint函数的使用方法
inpaint函数在OpenCV中的原型如下:
dst = cv2.inpaint(src, mask, dst, inpaintRadius, flags)
参数说明:
- src:输入图像,即待修复的原始图像。
- mask:掩膜图像,用于指定需要修复的区域。在掩膜图像中,需要修复的区域像素值为255(白色),其他区域像素值为0(黑色)。
- dst:输出图像,即修复后的图像。
- inpaintRadius:修复算法中使用的邻域半径。该参数决定了算法在修复每个像素时考虑的周围像素范围。半径越大,修复效果可能越平滑,但也可能丢失更多的细节。
- flags:算法标志,用于指定使用的修复算法。OpenCV提供了两种算法选项:cv2.INPAINT_NS和cv2.INPAINT_TELEA。前者是Navier-Stokes流体动力学算法的简化版本,后者是Telea算法。
鼠标事件回调函数cv2.setMouseCallback介绍
cv2.setMouseCallback(winname , MouseCallback)是一个对 winname 窗口鼠标状态的监视函数,当 winname 窗口上有鼠标动作时,即自动调用 MouseCallback 函数,相当于这个窗口的一个鼠标中断。在此函数前,应该拥有相应的窗口声明函数 cv2.namedWindow(winname)以被 setMouseCallback() 函数做捕获,确认操作窗口。
# 导入OpenCV包
import cv2 as cv
# 定义全局变量
point = (-1,-1)
# 编写回调函数
def action(event, x, y, flags, param):
global point
# 鼠标左键按下
if event == cv.EVENT_LBUTTONDOWN:
#左键按下更新全局变量
point = (x, y)
print("EVENT_LBUTTONDOWN")
print(x, ' ', y)
# 窗口声明
cv.namedWindow('drawing')
# 鼠标事件绑定
cv.setMouseCallback('drawing', action)
camera = cv.VideoCapture(0)
while True:
s, img = camera.read()
# 通过全局变量在制定位置绘制图像
cv.circle(img,point,4,(0,0,255),-1)
cv.putText(img,f"{point}",point,cv.FONT_HERSHEY_TRIPLEX,1,(0,0,255),1)
cv.imshow('drawing', img)
# 按 q 键退出
if cv.waitKey(1) & 0xFF == ord('q'):
break
camera.release()
cv.destroyAllWindows()
去水印步骤
- 打开图像或视频
- 通过鼠标涂抹水印区域mask
- 预处理mask,转换为单通道并膨胀
- 调用cv2.inpaint函数对水印去进行修复
注:对于视频的去水印,通过读取第一帧图像获取mask后,其余图像帧都可以使用该mask进行操作
实现代码
import cv2
import numpy as np
mode = False
drawing = False
# 鼠标回调函数
def draw_action(event, x, y, flags, param):
global ix, iy, drawing, mode, img
psize = 10
print(psize)
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.rectangle(mask, (ix, iy), (x, y), (100, 255, 0), -1)
cv2.rectangle(img, (ix, iy), (x, y), (100, 255, 0), -1)
else:
cv2.circle(mask, (x, y), psize, (100, 255, 0), -1)
cv2.circle(img, (x, y), psize, (100, 255, 0), -1)
cv2.imshow("frame", img)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.rectangle(mask, (ix, iy), (x, y), (100, 255, 0), -1)
cv2.rectangle(img, (ix, iy), (x, y), (100, 255, 0), -1)
else:
cv2.circle(mask, (x, y), psize, (100, 255, 0), -1)
cv2.circle(img, (x, y), psize, (100, 255, 0), -1)
def watermask_remove(img):
global mask
# 开始操作
# 设定要查找的颜色范围
lower_green = np.array([50, 50, 50])
upper_green = np.array([255, 255, 255])
hsv = cv2.cvtColor(mask, cv2.COLOR_BGR2HSV)
thresh = cv2.inRange(hsv, lower_green, upper_green)
scan = np.ones((5, 5), np.uint8)
cor = cv2.dilate(thresh, scan, iterations=1)
dst = cv2.inpaint(img, cor, 3, cv2.INPAINT_TELEA)
return dst
if __name__ == '__main__':
pmode = "video" # video image
path = "demo.png"
vieodpath = "1.mp4"
cap = cv2.VideoCapture(vieodpath)
if pmode == "video":
ret, img = cap.read()
else:
img = cv2.imread(path)
img_copy = np.copy(img)
mask = np.copy(img)
mask[:, :] = 0
# 通过绘制获取mask
cv2.imshow("frame", img)
cv2.namedWindow('frame')
cv2.setMouseCallback("frame", draw_action)
cv2.waitKey(0)
# 根据mask去水印
no_watermask_frame= watermask_remove(img_copy)
cv2.imshow('src', img_copy)
cv2.imshow('dst', no_watermask_frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
# # 创建视频编写器
# fourcc = cv2.VideoWriter_fourcc(*'mp4v')
# # out = cv2.VideoWriter('output' + datetime.now().strftime("%H-%M-%S") + '.mp4', fourcc, 20.0, (width, height))
#
# if pmode == "video":
# if cap.isOpened():
# cap.release()
# cap = cv2.VideoCapture(vieodpath)
# while (cap.isOpened()):
# ret, frame = cap.read()
# if ret:
# # 写入输出视频
# no_watermask_frame= watermask_remove(frame)
# # out.write(no_watermask_frame)
#
# # 显示帧
# cv2.imshow('frame', no_watermask_frame)
# #
#
# if cv2.waitKey(27) & 0xFF == ord('s'):
# # 释放资源
#
# break
#
# cap.release()
# # out.release()
# cv2.destroyAllWindows()
# else:
# nowaterprint_frame = waterprint(img)
# cv2.imshow('frame', nowaterprint_frame)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
效果如下:
使用cv2.inpaint函数进行图像修复,效果还是不佳,后续有空尝试训练去水印的AI模型。