- python 3.6.5
- openCV 4.0.1
基本思路:
- 提取ROI(感兴趣的区域,即水印所在的区域)
- 为水印创建蒙层
- 借助水印蒙层对图片进行修补
**提取ROI:**获取水印在图片中所在的区域,即像素值范围。可以有很多工具获得,我使用的是windows自带的画图工具。
使用画图工具获取水印范围后就可以使用切片了,roi = img[930:966,540:690]提取ROI。需要注意的是图片坐标与二维数组位置是相反的,图片坐标(x, y)中x表示像素点到图片左侧的距离,y表示像素点到图片顶部的距离,而二维数组位置(x, y)中x表示该像素点所在行数,y表示该像素点所在列数,两者虽然都是两个数字,但顺序正好相反。
**为水印创建蒙层:**通过对水印logo的观察可以发现,该水印只有一种颜色白色,因此我们只需要对白色这一种颜色进行处理即可。(测试时都是使用微博带水印的图,貌似微博水印都是白色,所以本文的去水印方法应该适用于微博去水印以及其他白色水印,时间原因,暂未做过多测试,在此只讨论方法。)为了精确处理白色,我们可以先将颜色格式有BGR转换为HSV,然后调用inRange()函数对ROI进行二值化处理。
最初看网上教程时对inRange中的范围不知道怎么设置,也不知时什么意义,后来发现都是些特定的HSV数值,根据下表处理自己想要处理的颜色即可。
HSV颜色体系:
二值化蒙层:
图片修复: 将水印二值化处理后需要使用dilate()函数对水印蒙层进行膨胀处理,这样去水印的效果更好。然后就是使用inPaint()函数利用膨胀后的蒙层对ROI进行修补,还原到原图中。
实现代码如下:
import cv2 as cv
import numpy as np
class WaterMark:
def Test(self,path):
img = cv.imread(path)
roi = img[930:966,540:690]
cv.imwrite('02.jpg',roi)
roi_hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
cv.imwrite('hsv.jpg',roi_hsv)
lower = np.array([0,0,221])
upper = np.array([180,30,255])
#创建水印蒙层
kernel = np.ones((3,3),np.uint8)
print(kernel)
cv.imwrite('kernel.jpg',kernel)
mask = cv.inRange(roi_hsv,lower,upper)
cv.imwrite(r'mask.jpg',mask)
#对水印蒙层进行膨胀操作
dilate = cv.dilate(mask,kernel,iterations=1)
cv.imwrite('dilate.jpg',dilate)
res = cv.inpaint(roi,dilate,7,flags=cv.INPAINT_TELEA)
cv.imwrite('res.jpg',res)
img[930:966,540:690] = res
cv.imwrite('modified.jpg',img)
if __name__ == '__main__':
path = 'girl.jpg'
w = WaterMark()
w.Test(path)
效果图:
其实微博的水印并不复杂,属于单色系水印,对于这种,其实不一定需要切片获取ROI
代码如下:
import cv2 as cv
import numpy as np
class WaterMark:
def Test(self,path):
img = cv.imread(path)
roi = img
cv.imwrite('02.jpg',roi)
roi_hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
cv.imwrite('hsv.jpg',roi_hsv)
lower = np.array([0,0,221])
upper = np.array([180,30,255])
#创建水印蒙层
kernel = np.ones((3,3),np.uint8)
print(kernel)
cv.imwrite('kernel.jpg',kernel)
mask = cv.inRange(roi_hsv,lower,upper)
cv.imwrite(r'mask.jpg',mask)
#对水印蒙层进行膨胀操作
dilate = cv.dilate(mask,kernel,iterations=1)
cv.imwrite('dilate.jpg',dilate)
res = cv.inpaint(roi,dilate,7,flags=cv.INPAINT_TELEA)
cv.imwrite('res.jpg',res)
img = res
cv.imwrite('modified.jpg',img)
if __name__ == '__main__':
path = 'girl.jpg'
w = WaterMark()
w.Test(path)