python + opencv去除图片水印(通过选择水印区域的方法)

python + opencv去除图片水印(通过选择水印区域的方法)

  • python 3.6.5
  • openCV 4.0.1

基本思路:

  1. 提取ROI(感兴趣的区域,即水印所在的区域)
  2. 为水印创建蒙层
  3. 借助水印蒙层对图片进行修补

**提取ROI:**获取水印在图片中所在的区域,即像素值范围。可以有很多工具获得,我使用的是windows自带的画图工具。
python + opencv去除图片水印(通过选择水印区域的方法)
使用画图工具获取水印范围后就可以使用切片了,roi = img[930:966,540:690]提取ROI。需要注意的是图片坐标与二维数组位置是相反的,图片坐标(x, y)中x表示像素点到图片左侧的距离,y表示像素点到图片顶部的距离,而二维数组位置(x, y)中x表示该像素点所在行数,y表示该像素点所在列数,两者虽然都是两个数字,但顺序正好相反。
python + opencv去除图片水印(通过选择水印区域的方法)
**为水印创建蒙层:**通过对水印logo的观察可以发现,该水印只有一种颜色白色,因此我们只需要对白色这一种颜色进行处理即可。(测试时都是使用微博带水印的图,貌似微博水印都是白色,所以本文的去水印方法应该适用于微博去水印以及其他白色水印,时间原因,暂未做过多测试,在此只讨论方法。)为了精确处理白色,我们可以先将颜色格式有BGR转换为HSV,然后调用inRange()函数对ROI进行二值化处理。

最初看网上教程时对inRange中的范围不知道怎么设置,也不知时什么意义,后来发现都是些特定的HSV数值,根据下表处理自己想要处理的颜色即可。
HSV颜色体系:
python + opencv去除图片水印(通过选择水印区域的方法)
python + opencv去除图片水印(通过选择水印区域的方法)
二值化蒙层:
python + opencv去除图片水印(通过选择水印区域的方法)
图片修复: 将水印二值化处理后需要使用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)

 

效果图:
python + opencv去除图片水印(通过选择水印区域的方法)
其实微博的水印并不复杂,属于单色系水印,对于这种,其实不一定需要切片获取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)

 

python + opencv去除图片水印(通过选择水印区域的方法)
python + opencv去除图片水印(通过选择水印区域的方法)