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

news2024/11/24 20:24:24

🍍原文: 基于 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.shape
    img = img[:, :, 0]
    p = np.zeros((r, c), np.uint8)
    a = 1
    b = 1
    for _s in range(s):
        for i in range(r):
            for j in range(c):
                x = (i + b * j) % r
                y = (a * i + (a * b + 1) * j) % c
                p[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.1

ca2 = 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 plt


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


Img = 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.1

ca2 = 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] = newImg

plt.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.coloradmin.cn/o/1672844.html

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

相关文章

Django模型进阶

接上一节 4.查询数据 在Django中,正向查询(Forward Query)和反向查询(Reverse Query)是ORM(Object-Relational Mapping,对象关系映射)中用于处理数据库表间关系时的两种查询方式&a…

代码随想录 打卡day23,24,25

1 二叉搜索树的最小绝对差 注意审题&#xff0c;题目当值说到是一个二叉搜索树&#xff0c;因此我们只需进行中序遍历即可&#xff0c;然后得到一个有序数组之后进行编辑&#xff0c;统计出来最小差。 class solution{ private:vector<int> vec;void traversal(TreeNode…

【经典文献】光声立体成像的对极几何

文献标题&#xff1a;《Epipolar Geometry of Opti-Acoustic Stereo Imaging》作者列表&#xff1a;Shahriar Negahdaripour发表期刊&#xff1a;IEEE Transactions on Pattern Analysis and Machine Intelligence发表年份&#xff1a;2007DOI链接&#xff1a;10.1109/TPAMI.20…

电流反馈型运放设计要点总结

目录 前言 基本架构 CFB和VFB运算放大器的差异 总结&#xff1a;电流反馈(CFB)与电压反馈(VFB) 前言 最近一个项目用到THS3491&#xff0c;发生了震荡&#xff0c;这是一个电流型反馈运放&#xff0c;借此机会&#xff0c;温故一下&#xff0c;电流运放的相关设计知识 基本架…

小米手机删除照片视频后没有释放手机存储空间

问题描述&#xff1a;小米手机11青春版&#xff0c;删除照片视频后&#xff0c;手机的存储空间没有变化&#xff1b; 问题原因&#xff1a;因为并没有真正的删除&#xff1b; 解决方案&#xff1a;手机 > 设置 > 我的设备 > 存储空间 > 应用公共文件(在最底部) &…

java多线程 线程交替执行(同步)的各种实现方案

目录 java多线程 线程交替执行&#xff08;同步&#xff09;的各种实现方案需求 指定具体执行顺序实现一&#xff1a;wait_notify机制 Thread标志位实现二&#xff1a;lock_condition机制 Thread标志位实现三&#xff1a;semaphore信号量 不指定具体执行顺序&#xff0c;只交…

深入学习指针5,与数组和指针相关的笔试题1(C语言)

前言 Hello,亲爱的小伙伴们&#xff0c;我又来了&#xff0c;&#xff0c;今天呢我们一起来学习一下C语言关于数组和指针的部分经典题目。如果觉得不错的话不要忘了点赞&#xff0c;收藏、关注&#xff0c;你的支持就是我更新的最大动力&#xff01;&#xff01; 好&#xff0…

什么是页分裂、页合并?

数据组织方式 在InnoDB存储引擎中&#xff0c;表数据都是根据主键顺序组织存放的&#xff0c;这种存储方式的表称为索引组织表(index organized table IOT)。 行数据&#xff0c;都是存储在聚集索引的叶子节点上的。而我们之前也讲解过InnoDB的逻辑结构图&#xff1a; 在I…

华为设备display查看命令

display version //查看版本信息 display current-configuration //查看配置详情 display this //查看当前视图有效配置 display ip routing-table //查看路由表 display ip routing-table 192.168.3.1 //查看去往3.1的路由 display ip interface brief //查看接口下ip信息 dis…

sudo apt-get update失败,怎么解决

本篇文章主要是从我的解决方案出发&#xff0c;因为个体差异性&#xff0c;对大家的帮助可能有限&#xff0c;不过大家也可以作为参考之一。 输入sudo apt-get update&#xff0c;结果一直显示&#xff1a; W: 无法下载 http://mirrors.aliyun.com/ubuntu/dists/jammy-securi…

利用一段代码轻松绕过PHP授权系统

第一步&#xff1a;首先你需要改名全局文件 比如说全局文件 common.php&#xff0c;那么 你将他改为core.php 第二步&#xff1a;创建文件 创建一个文件&#xff0c;和改名前的全局文件名称一样&#xff0c;然后把以下代码复制进去就OK了 代码如下&#xff1a; <?php…

20240513,常用算法(查找,排序,拷贝替换)

做着一些和考试无关的事情 常用查找算法——续 FIND_IF find_if //按条件查找元素&#xff0c;返回迭代器POS / END()find_if(beg,end,_Fred) _Fred函数或谓词&#xff08;返回BOOL类型的仿函数&#xff09; #include<iostream> #include<string> #includ…

【逆天OP懒狗的JAVA自学笔记--5.判断和循环】第二阶段始篇

文章目录 前言一、流程控制语句1.顺序结构&#xff08;最简单&#xff09;2.分支结构2.1 if 语句2.1.1 if语句的三种格式2.1.2 if 的注意事项 2.2 switch 语句2.2.1switch 的扩展知识 3.循环结构3.1 for 循环 扩展小点&#xff1a;//1.求和的变量不能定义在循环的里面&#xff…

韵搜坊(全栈)-- 前后端初始化

文章目录 前端初始化后端初始化 前端初始化 使用ant design of vue 组件库 官网快速上手&#xff1a;https://www.antdv.com/docs/vue/getting-started-cn 安装脚手架工具 进入cmd $ npm install -g vue/cli # OR $ yarn global add vue/cli创建一个项目 $ vue create ant…

WPF使用ItemsControl显示Object的所有属性值

对于上位机开发&#xff0c;我们有时候有这样的需求&#xff1a;如何显示所有的IO点位&#xff1f;比如有10个IO点位&#xff0c;那我们要写10个TextBlock去绑定这10个点位的属性&#xff08;本文暂时不考虑显示的样式&#xff0c;当然也可以考虑&#xff09;&#xff0c;当点位…

OBS插件--图片或视频源随着声音动态缩放

音效动态调整 应用此插件的源可以根据音效声音的高低进行动态的缩放。在本例中&#xff0c;我们在当前的场景里面添加了一个小喇叭的图片源&#xff0c;在这个图片源上引用这款滤镜插件&#xff0c;然后将VLC视频源的音效用于此插件的音效。设置完成后&#xff0c;场景中的小喇…

blender导出gltf模型混乱

最近用户给了几个blender文件&#xff0c;在blender打开是这样的&#xff1a; 我导出成gltf候&#xff0c;在本地打开时&#xff0c;底部发生了改变&#xff1a; 可以看出来&#xff0c;底部由原来的类型box变为了两个平面&#xff0c;后来我查了下blender里的属性设置&#xf…

三更草堂前后端分离个人博客项目的开发笔记

文章目录 项目实战-前后端分离博客系统1.课程介绍2.创建工程3.博客前台3.0 准备工作3.1 SpringBoot和MybatisPuls整合配置测试 3.1 热门文章列表3.1.0 文章表分析3.1.1 需求3.1.2 接口设计3.1.3 基础版本代码实现3.1.4 使用VO优化3.1.5 字面值处理 3.2 Bean拷贝工具类封装3.2 查…

flink优化案例

文章目录 一、flink join维表案例二、flink 双流join案例三、总结 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考(适用于flink1.13) 一、flink join维表案例 背景:flink sql join 维表。job业务不复杂&#xff0c;job写入性能比较差。维表数据大约每天…

【ubuntu20.04运行python文件时,报错No module named ‘rospkg’】

**问题原因&#xff1a;**一般来说&#xff0c;并不是真的缺少rospkg&#xff0c;而是系统中存在多个python版本导致的混乱 检查python版本 Ubuntu20.04 —— pyhon3.8 sudo apt-get install python3.8最新版本&#xff0c;如下图所示 查看python3.8的位置 whereis python…