[Opencv基础]水印,数字水印,频域水印(隐形水印)

水印,你在很多公司图片都会看到,里面都会加入图片都会有显式水印,或者半隐形水印。
平常加水印,只要将两张图片色值混合就没问题了

import cv2
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
img  = cv2.imread("lena.jpg")
img= cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
wm = cv2.imread("cang_wang.png")
wm = cv2.resize(wm,(364,40))
# wm = 255-wm
img1 = cv2.resize(img,(600,600))
//圈定感兴趣区域
imgROI = img1[600-wm.shape[0]:600,600-wm.shape[1]:600]
//图片透明度混合
cv2.addWeighted(imgROI,0.5,wm,0.5,0,imgROI)
plt.figure(figsize=(11,11))
plt.imshow(img1)

[Opencv基础]水印,数字水印,频域水印(隐形水印)_第1张图片
这里引用到Opencv 图像叠加 添加水印

数字水印是怎样的?
1、预处理隐藏信息
首先将需要加密的图像进行转换为二值图像,其中只包含两个灰度级0和1。其中0对应黑色,1对应白色。在opencv中其实没有二值图像,我们可以将二值图像理解为特殊的灰度图像。由于需要将隐藏信息嵌入图片的第0位(每个像素点分出一个bit位来存储信息)所以被隐藏信息图像的最高灰度级必须为1,最低为0。

对图像进行二值化可以利用以下方法:

s_black = s[:,:]<128 # s为需要被隐藏的图片 s_black记录灰度值小于128的像素的位置
s[s_black] = 0 # 将灰度值小于128的灰度值置为0
s_white = s[:]>=128 # s_white记录灰度值大于128的像素的位置
s[s_white] = 1 # 将灰度值大于128的灰度值置为1
这样就得到被标记为0和1的矩阵

彩色图片色值0~255,我们可以借用RGB其中一个色值,然后转为二进制值,最后一位用来记录签名值。因为最后一位色值其实变化很小,用来记录二值化干扰非常小。

# 因为没有现成的二值图像,在此的s图像是一个包含黑色和白色的彩色图像,因此在这里需要阈值化处理
#这里水印图设置成原图大小,不然不能使用与或运算,如果有人知道抽取roi区域做与或运算的方法也可以告诉我
wm_2 = cv2.resize(wm,(img.shape[1],img.shape[0]))
plt.imshow(wm_2)
s_black = wm_2[:,:]<128
wm_2[s_black] = 1
s_white = wm_2[:]>=128
wm_2[s_white] = 0

# r, c = img.shape
r = img.shape[0]
c = img.shape[1]
 
# 构造提取原始图像高7位矩阵
t255 = np.ones((r, c, 3), dtype=np.uint8)*254
 
# # 获取原始图像的高七位
demo_h7 = np.bitwise_and(img, t255)
# plt.imshow(demo_h7)
 
# # 嵌入水印
demo_s_in = np.bitwise_or(demo_h7, wm_2)
# plt.imshow(cv2.hconcat([demo_h7,demo_s_in]))
 
# 生成提取矩阵
t1 = np.ones((r, c, 3), dtype=np.uint8)
s_out = np.bitwise_and(demo_s_in, t1)
s_out_white = s_out[:]<1
s_out[s_out_white] = 255
# cv2.imshow("s_out", s_out)
plt.figure(figsize=(11,11))
plt.imshow(cv2.hconcat([demo_h7,demo_s_in,s_out]))

[Opencv基础]水印,数字水印,频域水印(隐形水印)_第2张图片
[Opencv基础]水印,数字水印,频域水印(隐形水印)_第3张图片
可以看出加了水印的图,其实和原图没有太大的差别。
因为我本来水印图色值还是有拉伸的,直接转化为0,1两个数字后,再和原图或值合并。
所以还原回来看水印的还原还是有区域无法正常显示。

数字水印的方式,其实抗干扰性非常之差,稍微进行

这里应用OpenCv图像处理——数字水印

频域水印
所谓频域水印,首先需要了解傅里叶变换

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('lena.jpg',0) #直接读为灰度图像
img = cv2.resize(img,(300,300))

wm = cv2.imread("cang_wang.png", 0)
wm = cv2.resize(wm,(200,50))
wm = 255-wm

#快速傅里叶变换算法得到频率分布
f = np.fft.fft2(img)
#默认结果中心点位置在左上角,转移到中间
fshift = np.fft.fftshift(f)
#取绝对值:将复数变化成实数
#取对数的目的为了将数据变化到0-255
#fshift是复数,求绝对值结果才是振幅
s1 = np.log(np.abs(fshift))

#求相位,相位和振幅是频域两个很重要的结果
#振幅只是记录图片的明暗,而相位才是记录图像的形状
s1_angle = np.angle(fshift)

#将水印放入频域
fshift2 = fshift.copy()
fshift2[0:50, 0:200] += wm *50.0
fshift2[-50:, -200:] += cv2.flip(wm, -1) *50.0

s2 = np.log(np.abs(fshift2))

# 逆变换
f1shift2 = np.fft.ifftshift(fshift2)
img_back2 = np.fft.ifft2(f1shift2)
#出来的复数,无法显示,转成实数
img_back2 = np.abs(img_back2)

f1shift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f1shift)
#出来的是复数,无法显示
img_back = np.abs(img_back)
plt.figure()
plt.imshow(img,'gray')
plt.figure()
plt.imshow(wm, 'gray')
plt.figure()
plt.imshow(s1,'gray')
plt.figure()
plt.imshow(s2,'gray')
plt.figure()
plt.imshow(img_back,'gray')

plt.figure()
plt.imshow(img_back2,'gray')

原图
[Opencv基础]水印,数字水印,频域水印(隐形水印)_第4张图片
水印图
在这里插入图片描述
频域图
[Opencv基础]水印,数字水印,频域水印(隐形水印)_第5张图片
加水印后频域图
[Opencv基础]水印,数字水印,频域水印(隐形水印)_第6张图片
频域逆转换后图
[Opencv基础]水印,数字水印,频域水印(隐形水印)_第7张图片
频域加水印后逆转换后图
[Opencv基础]水印,数字水印,频域水印(隐形水印)_第8张图片
关于opencv使用傅里叶变换,可以参照一下这个文章OpenCV学习笔记-傅里叶变换
关于频域水印再受到变换后可能出现的问题,可以参照这篇文章有意思的数字盲水印的简单的实现
基本旋转平移、光暗调整等操作,不会对水印有太大影响,但是通过模糊算法后,水印会被刷除,但是锐化算法不会有太大影响。

你可能感兴趣的:(opencv,计算机视觉,pytorch)