数字水印 | Python 基于离散小波变换 DWT 的图像水印嵌入(上)

🍍原文: 基于 dwt (离散小波变换) 实现彩色图像水印嵌入部分_1.0

🍍写在前面: 本文在原文的基础上进行了代码补全。



正文

本文的内容主要为:水印图像经过 A r n o l d \mathsf{Arnold} Arnold 置乱算法后,通过离散小波变换进行嵌入。

在这里插入图片描述

c A \mathsf{cA} cA 等为原始图像的小波系数, c a \mathsf{ca} ca 等为水印图像的小波系数,嵌入公式如下:

{ c A 3 ′ = c A 3 + a 1 × c a 1 c H 3 ′ = c H 3 + a 2 × c h 1 c V 3 ′ = c V 3 + a 3 × c v 1 c D 3 ′ = c D 3 + a 4 × c d 1 \left\{\begin{matrix} cA'_3 = cA_3 + a_1 \times ca_1\\ cH'_3 = cH_3 + a_2 \times ch_1 \\ cV'_3 = cV_3 + a_3 \times cv_1 \\ cD'_3 = cD_3 + a_4 \times cd_1 \end{matrix}\right. cA3=cA3+a1×ca1cH3=cH3+a2×ch1cV3=cV3+a3×cv1cD3=cD3+a4×cd1

为了验证方便,后文代码将上述公式中的三级小波 c A 3 \mathsf{cA_3} cA3 变换与一级小波 c a 1 \mathsf{ca_1} ca1 变换的嵌入,简化为了一级小波 c A 1 \mathsf{cA_1} cA1 变换与一级小波 c a 1 \mathsf{ca_1} ca1 变换的嵌入。当然,嵌入效果不会很好。

看得出来嵌入效果不是很好😇

为了使结果仍然为彩色图像,本文在小波变换前将原始图像的 R , G , B \mathsf{R,G,B} R,G,B 通道分离,仅在 B ( b l u e ) \mathsf{B(blue)} B(blue) 通道中嵌入水印。嵌入完成后,再将 R , G , B \mathsf{R,G,B} R,G,B 三个通道合并。



1 代码说明

1.1 Arnold

A r n o l d \mathsf{Arnold} Arnold 置乱算法如下,即粘即用:

def arnold(img, s):  # s置乱次数r, c, d = img.shapeimg = img[:, :, 0]p = np.zeros((r, c), np.uint8)a = 1b = 1for _s in range(s):for i in range(r):for j in range(c):x = (i + b * j) % ry = (a * i + (a * b + 1) * j) % cp[x, y] = img[i, j]img = np.copy(p)  # 深复制return p

以上代码就是对 A r n o l d \mathsf{Arnold} Arnold 公式的实现。如果不知道 A r n o l d \mathsf{Arnold} Arnold 公式是什么,那么自然是看不懂的😇

参考自博客:Python 基于位平面的信息隐藏算法 阿诺德置乱算法



1.2 读取图像

分别读取 I m g \mathsf{Img} Img 原始图像和 w a t e r I m g \mathsf{waterImg} waterImg 水印图像:

Img = cv2.imread('white_bear.jpg')
# 原始图像调序
b, g, r = cv2.split(Img)
Img = cv2.merge([r, g, b])waterImg = cv2.imread('uestc_logo.jpg')
# 水印图像调序
b, g, r = cv2.split(waterImg)
waterImg = cv2.merge([r, g, b])

cv2 读取图片时的通道顺序为 B、G、R,而 PIL 显示图片时的通道顺序为 R、G、B,因此显示出来的图片颜色会改变,需要对图像通道进行调序。

参考自博客:CV2 读取图片,图片颜色发生改变解决方案



1.3 小波变换

首先修剪原始图像为水印图像的大小,然后分离出原始图像的 B \mathsf{B} B 通道:

img = cv2.resize(Img, (r, c))  # 修剪原始图像
(b, g, r) = cv2.split(img)  # 分离通道

接着,直接调用库函数 pywt.dwt2 实现小波变换:

# 水印图像一级小波变换
coeffs1 = pywt.dwt2(waterImg, 'haar')
ca1, (ch1, cv1, cd1) = coeffs1# 原始图像B通道一级小波变换
coeffs2 = pywt.dwt2(b, 'haar')
ca2, (ch2, cv2, cd2) = coeffs2

如果没有 p y w t \mathsf{pywt} pywt 库则需要进行安装:

pip install PyWavelets


1.4 嵌入水印

就是对文首的嵌入公式的实现:

# 自定义嵌入系数,可用随机数处理
a1 = 0.1
a2 = 0.2
a3 = 0.1
a4 = 0.1ca2 = ca2 + ca1 * a1
ch2 = ch2 + ch1 * a2
cv2 = cv2 + cv1 * a3
cd2 = cd2 + cd1 * a4


1.5 小波逆变换

第一句代码才是小波逆变换:

newImg = pywt.idwt2((ca2, (ch2, cv2, cd2)), "haar")
merged = np.ones(img.shape, dtype=np.uint8)
merged[:, :, 0] = r
merged[:, :, 1] = g
merged[:, :, 2] = newImg

后面的代码是在对通道进行合并。可以看出,嵌入了水印的 n e w I m g \mathsf{newImg} newImg 被我们放在了 B \mathsf{B} B 通道,而 R , G \mathsf{R,G} R,G 通道保持原样。



2 完整代码

import cv2
import pywt
import numpy as np
import matplotlib.pyplot as pltdef arnold(img, s):  # s是置乱次数r, c, d = img.shapeimg = img[:, :, 0]p = np.zeros((r, c), np.uint8)a = 1b = 1for _s in range(s):for i in range(r):for j in range(c):x = (i + b * j) % ry = (a * i + (a * b + 1) * j) % cp[x, y] = img[i, j]img = np.copy(p)  # 深复制return pImg = cv2.imread('white_bear.jpg')  # 原始图像
b, g, r = cv2.split(Img)
Img = cv2.merge([r, g, b])water = cv2.imread('uestc_logo.jpg')  # 只是为了后面的展示
b, g, r = cv2.split(water)
water = cv2.merge([r, g, b])waterImg = cv2.imread('uestc_logo.jpg')  # 水印图像
b, g, r = cv2.split(waterImg)
waterImg = cv2.merge([r, g, b])
waterImg = arnold(waterImg, 5)  # Arnold置乱# 原始图像尺寸数据
R = Img.shape[0]
C = Img.shape[1]# 水印图像尺寸数据
r = waterImg.shape[0]
c = waterImg.shape[1]img = cv2.resize(Img, (r, c))  # 修剪原始图像
(b, g, r) = cv2.split(img)  # 分离通道# 水印图像一级小波变换
coeffs1 = pywt.dwt2(waterImg, 'haar')
ca1, (ch1, cv1, cd1) = coeffs1# 原始图像B通道一级小波变换
coeffs2 = pywt.dwt2(b, 'haar')
ca2, (ch2, cv2, cd2) = coeffs2# 自定义嵌入系数,可用随机数处理
a1 = 0.1
a2 = 0.2
a3 = 0.1
a4 = 0.1ca2 = ca2 + ca1 * a1
ch2 = ch2 + ch1 * a2
cv2 = cv2 + cv1 * a3
cd2 = cd2 + cd1 * a4# 对小波系数进行逆变换
newImg = pywt.idwt2((ca2, (ch2, cv2, cd2)), "haar")
merged = np.ones(img.shape, dtype=np.uint8)
merged[:, :, 0] = r
merged[:, :, 1] = g
merged[:, :, 2] = newImgplt.subplot(2, 2, 1)
plt.title("Watermark", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(water)plt.subplot(2, 2, 2)
plt.title("Arnold Watermark", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(waterImg)plt.subplot(2, 2, 3)
plt.title("Original", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(Img)plt.subplot(2, 2, 4)
plt.title("Watermarked", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(merged)plt.savefig('test.jpg', dpi=400)
plt.show()


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/11667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue+springboot用户注销功能

vue文件前端 <el-button type"warning" plain click"handleDeletion">注 销</el-button> // 注销 const handleDeletion (userName) > {ElMessageBox.confirm(注销该用户所有信息后无法恢复&#xff0c;您确认注销吗?, 注销确认, { type…

实现日期类

日期类的实现主要是去学习使用operator的 日期类就是计算日期之间的天数&#xff0c;日期与&#xff08;日期&#xff0c;天数&#xff09;的相加减 比如日常生活中我们可以计算日期加天数&#xff0c;日期减天数&#xff0c;日期减日期&#xff0c; 但没有日期加日期的说法 日…

M-有效算法

在赛场上&#xff0c;脑子就两个字“二分”&#xff0c;一点思路都没&#xff0c;完全不知道二分谁&#xff0c;怎么二分&#xff0c;从哪入手。隐隐约约也知道要变换公式&#xff0c;可惜没坚持这个想法。脑子里全是把k分离出来&#xff0c;赛后看了题解才知道&#xff0c;应该…

LeetCode 力扣题目:买卖股票的最佳时机 IV

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

MQTT学习(二)

订阅主题和订阅确认 SUBSCRIBE——订阅主题 之前的CONNECT报文&#xff0c;分为 固定报头&#xff1a;必须存在&#xff0c;用于描述报文信息。里面有指出什么类型的报文&#xff0c;报文的等级。可变报头&#xff1a;不一定存在。主要看什么样子类型的报文。有效载荷部分&a…

LoRA Land: 310个经微调的大语言模型可媲美GPT-4

摘要 低秩自适应 (LoRA) 已成为大语言模型 (LLM) 参数有效微调 (PEFT) 中最广泛采用的方法之一。LoRA 减少了可训练参数的数量和内存使用,同时达到了与全面微调相当的性能。该研究旨在评估在实际应用中训练和服务使用 LoRA 微调的 LLM 的可行性。首先,该研究测量了在 10 个基础…

js基础-数组-事件对象-日期-本地存储

一、大纲 一、获取元素位置 在JavaScript中&#xff0c;获取一个元素在页面上的位置可以通过多种方法实现。以下是一些常见的方法&#xff1a; getBoundingClientRect() getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。它提供了元素的left、top、right和bo…

Vue的学习 —— <vue响应式基础>

目录 前言 正文 单文件组件 什么是单文件组件 单文件组件使用方法 数据绑定 什么是数据绑定 数据绑定的使用方法 响应式数据绑定 响应式数据绑定的使用方法 ref() 函数 reactive()函数 toRef()函数 toRefs()函数 案例练习 前言 Vue.js 以其高效的数据绑定和视图…

探索大语言模型代理(Agent):研究背景、通用框架与未来展望

引言 近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;在智能代理&#xff08;Agent&#xff09;领域中的应用已成为研究的热点。这些代理不仅能够模拟人类的认知过程&#xff0c;还能在复杂的社会环…

CNN/TCN/LSTM/BiGRU-Attention到底哪个模型效果最好?注意力机制全家桶来啦!

​ 声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 数据介绍 效果展示 原理简介 代…

数字人解决方案——AniTalker声音驱动肖像生成生动多样的头部说话视频算法解析

1.概述 AniTalker是一款先进的AI驱动的动画生成工具&#xff0c;它超越了简单的嘴唇同步技术&#xff0c;能够精准捕捉并再现人物的面部表情、头部动作以及其他非言语的微妙动态。这不仅意味着AniTalker能够生成嘴型精准同步的视频&#xff0c;更重要的是&#xff0c;它还能够…

使用Dockerfile配置Springboot应用服务发布Docker镜像-16

创建Docker镜像 springboot-docker模块 这个应用可以随便找一个即可&#xff0c;这里不做详细描述了。 pom.xml 依赖版本可参考 springbootSeries 模块中pom.xml文件中的版本定义 <dependencies><dependency><groupId>com.alibaba.cloud</groupId>…

[数据集][图像分类]杂草分类数据集17509张9类别

数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;17509 分类类别数&#xff1a;9 类别名称:["chineseapple","lantana","negatives","parkinsonia","part…

48-Qt控件详解:Buttons Containers2

一 Group Box:组合框 #include "widget.h"#include<QGroupBox> #include<QRadioButton> #include<QPushButton> #include<QVBoxLayout>//可以在水平方向和垂直方向进行排列的控件&#xff0c;QHBoxLayout/QVBoxLayout #include <QGridLa…

解决宝塔Nginx和phpMyAdmin配置端口冲突问题

问题描述 在对基于宝塔面板的 Nginx 配置文件进行端口修改时&#xff0c;我注意到 phpMyAdmin 的端口配置似乎也随之发生了变化&#xff01; 解决方法 官方建议在处理 Nginx 配置时&#xff0c;应避免直接修改默认的配置文件&#xff0c;以确保系统的稳定性和简化后续的维护…

大数据可视化实验三——数据可视化工具使用

目录 一、实验目的... 1 二、实验环境... 1 三、实验内容... 1 1. 下载并安装Tableau软件.. 1 2. 使用HTML5绘制Canvas图形.. 2 3. 使用HTML5编写SVG 图形... 5 4. 使用R 语言编写可视化实例.. 7 四、总结与心得体会... 7 五、思考问题... 8 一、实验目的 1&#xff…

C++-Linux工程管理

1 Makefile和CMake实践 1.1 Makefile 参考 简介&#xff1a; Makefile是一种用于自动化构建和管理程序的工具。它通常用于编译源代码、链接对象文件以生成可执行文件或库文件。Makefile以文本文件的形式存在&#xff0c;其中包含了一系列规则和指令&#xff0c;用于描述程序的…

python数据分析——seaborn绘图1

参考资料&#xff1a;活用pandas库 matplotlib库是python的和兴绘图工具&#xff0c;而seaborn基于matplotlib创建&#xff0c;它为绘制统计图提供了更高级的接口&#xff0c;使得只用少量代码就能生成更美观、更复杂的可视化效果。 seaborn库和pandas以及其他pydata库&#xf…

OpenHarmony 实战开发——移植通信子系统

通信子系统目前涉及Wi-Fi和蓝牙适配&#xff0c;厂商应当根据芯片自身情况进行适配。 移植指导 Wi-Fi编译文件内容如下&#xff1a; 路径&#xff1a;“foundation/communication/wifi_lite/BUILD.gn” group("wifi") {deps [ "$ohos_board_adapter_dir/ha…

C++基础与深度解析 | 数组 | vector | string

文章目录 一、数组1.一维数组2.多维数组 二、vector三、string 一、数组 1.一维数组 在C中&#xff0c;数组用于存储具有相同类型和特定大小的元素集合。数组在内存中是连续存储的&#xff0c;并且支持通过索引快速访问元素。 数组的声明&#xff1a; 数组的声明指定了元素的…