水印,你在很多公司图片都会看到,里面都会加入图片都会有显式水印,或者半隐形水印。平常加水印,只要将两张图片色值混合就没问题了
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、预处理隐藏信息首先将需要加密的图像进行转换为二值图像,其中只包含两个灰度级0和1。其中0对应黑色,1对应白色。在opencv中其实没有二值图像,我们可以将二值图像理解为特殊的灰度图像。由于需要将隐藏信息嵌入图片的第0位(每个像素点分出一个bit位来存储信息)所以被隐藏信息图像的最高灰度级必须为1,最低为0。
对图像进行二值化可以利用以下方法:
s_black = s[:,:]<128 # s为需要被隐藏的图片 s_black记录灰度值小于128的像素的位置s[s_black] = 0 # 将灰度值小于128的灰度值置为0s_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]))
可以看出加了水印的图,其实和原图没有太大的差别。因为我本来水印图色值还是有拉伸的,直接转化为0,1两个数字后,再和原图或值合并。所以还原回来看水印的还原还是有区域无法正常显示。
数字水印的方式,其实抗干扰性非常之差,稍微进行
这里应用OpenCv图像处理——数字水印
频域水印所谓频域水印,首先需要了解傅里叶变换
import cv2 import numpy as np import matplotlib.pyplot as pltimg = 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.0s2 = 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使用傅里叶变换,可以参照一下这个文章OpenCV学习笔记-傅里叶变换
关于频域水印再受到变换后可能出现的问题,可以参照这篇文章有意思的数字盲水印的简单的实现
基本旋转平移、光暗调整等操作,不会对水印有太大影响,但是通过模糊算法后,水印会被刷除,但是锐化算法不会有太大影响。
源码有哦 记得加群:1136192749