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

news2024/11/29 2:34:59

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

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



正文

修改了尺寸变换导致的图像失真问题,同时简化了部分代码。

在这里插入图片描述

效果确实很好😉



1 通道调序的简化

将之前的两句代码简化为了一句代码:

Img_path = 'white_bear.jpg'
Img = cv2.imread(Img_path)
Img = Img[:, :, [2, 1, 0]]  # 调整通道顺序

这里的 I m g \mathsf{Img} Img 是一个三维数组,其中每个维度分别代表:

  • 第一个维度是图像的高度(或行数)
  • 第二个维度是图像的宽度(或列数)
  • 第三个维度是图像的通道数

由于 c v 2 \mathsf{cv2} cv2 读取图像通道的顺序是 B , G , R \mathsf{B,G,R} B,G,R,因此上述代码将其更改为 R , G , B \mathsf{R,G,B} R,G,B 顺序。



2 多级小波变换

# 水印图像一级小波变换
coeffs1 = pywt.wavedec2(waterImg_new, 'db2', level=1)
[ca, (ch1, cv1, cd1)] = coeffs1

# 原始图像B通道三级小波变换
coeffs2 = pywt.wavedec2(b, 'db2', level=3)
[cA, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)] = coeffs2
  • 'db2':是选定的小波类型。这里是 D a u b e c h i e s \mathsf{Daubechies} Daubechies 长度为 2 的整数系小波。
  • level=3:是小波分解的级别。级别决定了分解的深度,也就是小波变换的层数。


3 图像尺寸裁剪

由嵌入公式可以看出, c A \mathsf{cA} cA 等的形状要和 c a \mathsf{ca} ca 等的形状相同,否则无法相加:

cA = cA + ca * a1
cH3 = cH3 + ch1 * a2
cV3 = cV3 + cv1 * a3
cD3 = cD3 + cd1 * a4

而每做一次小波变换,图像的尺寸都会减小到原本的 1 / 2 1/2 1/2

[cA, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)] = coeffs2

其中 c H 3 \mathsf{cH3} cH3 c H 2 \mathsf{cH2} cH2 1 / 2 1/2 1/2 c H 2 \mathsf{cH2} cH2 c H 1 \mathsf{cH1} cH1 1 / 2 1/2 1/2。因此,定义了以下三个函数为图像计算尺寸。




m a x R C \mathsf{maxRC} maxRC 函数比较原始图像的长度和宽度,并返回其中的较大值作为原始图像的新尺寸:

def maxRC(Img_path):
    Img = cv2.imread(Img_path, 0)
    R = Img.shape[0]
    C = Img.shape[1]
    RC_new = max(R, C)
    return RC_new

裁剪后的原始图像比例为 1 : 1 1:1 1:1,且边长为 m a x ( R , C ) \mathsf{max(R, C)} max(R,C)

i n c h e s 3 \mathsf{inches3} inches3 函数计算水印图像的新尺寸,它需要是原始图像的 ( 1 / 2 ) t i m e s \mathsf{(1/2)^{times}} (1/2)times 倍:

def inches3(num, times):
    for i in range(times):
        num = round((num/2 + 1))
    return num


def Icm(RC_new):
    rc_new = inches3(RC_new, 2)
    return rc_new

其中, t i m e s = 3 − 1 = 2 \mathsf{times}=3-1=2 times=31=2 即原始图像的小波变换级别减去水印图像的小波变换级别。

个人理解:原始图像的小波变换级别是 3 3 3,水印图像的小波变换级别是 1 1 1。要使 c A \mathsf{cA} cA 等和 c a \mathsf{ca} ca 等能够相加,那么需要它们的尺寸相同。参考下图,根据 c A \mathsf{cA} cA 的尺寸,以及水印图像的小波变换级别是 1 1 1 这一条件,去倒推水印图像的新尺寸应该是多少。

在这里插入图片描述



4 完整代码

i n c h e s 3 \mathsf{inches3} inches3 函数和 I c m \mathsf{Icm} Icm 函数应该还可以简化,名字也是取得莫名其妙,可以自己改一下😇

import cv2
import pywt
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt


def arnold(img, 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


def inches3(num, times):
    for i in range(times):
        num = round((num/2 + 1))
    return num


def Icm(RC_new):
    rc_new = inches3(RC_new, 2)
    return rc_new


def maxRC(Img_path):
    Img = cv2.imread(Img_path, 0)
    R = Img.shape[0]
    C = Img.shape[1]
    RC_new = max(R, C)
    return RC_new


# 读取图像
Img_path = 'white_bear.jpg'
waterImg_path = 'uestc_logo.jpg'
Img = cv2.imread(Img_path)
Img = Img[:, :, [2, 1, 0]]

water = cv2.imread(waterImg_path)  # 只是为了后面展示用
water = water[:, :, [2, 1, 0]]

waterImg = cv2.imread(waterImg_path)
waterImg = waterImg[:, :, [2, 1, 0]]
waterImg = arnold(waterImg, 5)


# 修改原始图像的尺寸
RC_new = maxRC(Img_path)
Img_new = cv2.resize(Img, (RC_new, RC_new))
(r, g, b) = cv2.split(Img_new)

# 修改水印图像的尺寸
rc_new = Icm(RC_new)
waterImg_new = cv2.resize(waterImg, (rc_new, rc_new))


# 水印图像一级小波变换
coeffs1 = pywt.wavedec2(waterImg_new, 'db2', level=1)
[ca, (ch1, cv1, cd1)] = coeffs1

# 原始图像B通道三级小波变换
coeffs2 = pywt.wavedec2(b, 'db2', level=3)
[cA, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)] = coeffs2


# 自定义嵌入系数
a1 = 0.1
a2 = 0.2
a3 = 0.1
a4 = 0.1

cA = cA + ca * a1
cH3 = cH3 + ch1 * a2
cV3 = cV3 + cv1 * a3
cD3 = cD3 + cd1 * a4


# 对小波系数进行逆变换
newImg = pywt.waverec2([cA, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)], 'db2')

merged = np.ones(Img_new.shape, dtype=np.uint8)
merged[:, :, 0] = r
merged[:, :, 1] = g
merged[:, :, 2] = newImg

Img_water = Image.fromarray(merged)
Img_water = Img_water.resize((808, 808), Image.LANCZOS)  # 重新调整大小,抗锯齿


#  画图
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/1670537.html

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

相关文章

15W 3KVAC隔离 宽电压输入 AC/DC 电源模块——TP15AL系列

TP15AL系列产品是一款小体积裸板式电源,该系列电源输出功率为15W,具有低漏电流小于0.35mA,隔离耐压高达3KV等特点。产品安全可靠,EMC性能好,该系列产品广泛应用于智能家居、充电桩、安防、物联、工控等行业中,如应用于电磁兼容比较恶劣的环境…

Kerberos修改协议为TCP

部署前 修改模板/home/cloud-setup/deploy-forklift/mids/forklift-basic/kde/v1.0/impl/plays/roles/krb5-client/templates/krb5.conf.j2 添加如下参数 udp_preference_limit 1 部署后 界面修改 添加如下参数,并勾选下发配置按钮,重启刷新服务

Linux-04

账号管理 添加账号 useradd 选项 用户名 useradd -m dai删除帐号 userdel 选项 用户名 userdel -r dai修改帐号 usermod 选项 用户名usermod -d /home/user dai (修改位置)切换帐号 su username su dai退出账号 exit $表示普通用户 #表示超级用户&#…

源代码防泄密的关键点:烧录管控

源代码作为企业技术核心的一部分,其保密性和安全性显得尤为重要。然而,随着开源文化的发展,以及开发过程中不可避免的与外界交流,源代码防泄密工作面临着前所未有的挑战。特别是在烧录过程中,由于涉及到硬件层面的操作…

PyWebIO,用 Python 写网站

在Python的世界里,PyWebIO是一个简单而强大的库,它能让你的Python脚本快速拥有一个交互式的网页界面。想象一下,你不需要懂得前端开发,就能创建出用户友好的网页应用,这是多么酷的一件事!今天,我…

排序-快速排序(Quick Sort)

快排的简介 快速排序(Quick Sort)是一种高效的排序算法,采用分治法的策略,其基本思想是选择一个基准元素,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据要…

aop获取方法运行时间

Slf4j Component Aspect//aop类 public class TimeAspect {/*Around 环绕通知 用ProceedingJoinPoint Before 前置通知 用JoinPoint(是ProceedingJoinPoint的父类型),用它可以获得方法执行的相关信息,如目标类名,方法…

我是如何免费抵御一个多月的 DDos/CC 攻击的?

今天明月给大家详细分享一下我的博客是如何免费抵御了长达一个多月的 DDos/CC 攻击的,在【现在 DDos/CC 攻击门槛低的可怕!】一文里明月就说过现在 DDos/CC 攻击几乎是没有门槛的,任何一个老鼠屎在群里看到你的博客都可以轻松便捷的发动一次 …

ADOP带你了解:800G OSFP光收发器:演进发布

引言 随着云计算、大数据和人工智能等技术的不断进步,对数据中心的带宽和处理能力要求也在不断提高。在这样的背景下,800G OSFP光收发器的问世,为我们提供了更高速度和更高效率的数据传输解决方案。 800G OSFP光收发器演进路线 路线 1&…

CSS3私有前缀+新增盒模型相关属性+新增背景属性(如果想知道CSS3私有前缀、新增盒模型相关属性的知识点,那么只看这一篇就足够了!)

前言:CSS3 是CSS2 的升级版本,它在CSS2 的基础上,新增了很多强大的新功能,从而解决一些实际面临的问题。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 先让我们看一下本篇文章的…

vue3 自定义调控参数-简易生成器

vue3 自定义调控参数-简易生成器 文章目录 封装生成器控件如下父组件使用如下: 此功能好像是某厂的在线视频笔试题,当时写完也没有结果。。。我觉得此 demo 适用场景:自定义动态表单时需要定制字段、用户自定义信息等 封装生成器控件如下 /…

阿里云短信提示被攻击怎么解决!!

你是否收到过这样的短信,【阿里云】尊敬的用户:您的IP: 实例名称: 受到攻击流量已超过云盾DDoS基础防护的带宽峰值,服务器的所有访问已被屏蔽,如果35分钟后攻击停止将自动解除否则会延期解除。详情请登录云盾控制台DDo…

SPSS之主成分分析

SPSS中主成分分析功能在【分析】--【降维】--【因子分析】中完成(在SPSS软件中,主成分分析与因子分析均在【因子分析】模块中完成)。 求解主成分通常从分析原始变量的协方差矩阵或相关矩阵着手。 (1)当变量取值的度量…

MySQL中的子查询

子查询,在一个查询语句中又出现了查询语句 子查询可以出现在from和where后面 from 表子查询(结果一般为多行多列)把查询结果继续当一张表对待 where 标量子查询(结果集只有一行一列)查询身高最高的学生,查询到一个最高身高 列子查询(结果集只有一行多列) 对上表进行如下操作 …

STM32 PWM 计数器模式和对齐

STM32 PWM 计数器模式和对齐 1. TIM高级定时器简介2. TIM计数模式2.1 向上计数2.2 向下计数2.3 中心对齐模式(向上/向下计数)2.4 重复计数 3. PWM输出模式3.1 举例看下PWM中心对齐模式,设置参数如下: 4. FOC中PWM相关设置说明4.1 …

webpack如何自定义一个loader

我们在使用脚手架的搭建项目的时候往往都会帮我们配置好所需的loader,接下来讲一下我们要如何自己写一个loader应用到项目中(完整代码在最后) 1. 首先搭建一个项目并找到webpack配置文件(webpack.config.js) 在modul…

arcgis_滑坡易发性评价数据处理过程

arcgis_LSM数据处理过程 地形因子处理环境因子处理获取坐标点的方法arcgis问题arcgis进行克里格插值更改投影方式中国地质数据下载站python矢量转栅格重采样设置像元大小一致,设置环境保证栅格对齐 地形因子处理 原始数据:DEM Elevation: 重采样 Slope、Aspect 设置环境保障…

java入门详细教程——day01

目录 1. Java入门 1.1 Java是什么? 1.2 Java语言的历史 1.3 Java语言的分类 1.4 Java语言的特点 1.4.1 先编译再解释运行 1.4.2 跨平台 1.5 JRE和JDK(记忆) 1.6 JDK的下载和安装(应用) 1.6.1 下载 1.6.2 安…

四款不同类型的企业防泄密软件推荐

在数字化快速发展的今天,企业数据的安全与保密显得愈发重要。防泄密软件作为一种专门的数据保护工具,已经逐渐成为企业不可或缺的安全屏障。本文将深入探讨防泄密软件对企业的意义,并介绍一些市面上主流的防泄密软件。 首先,防泄密…

redis的跳表

typedef struct zskiplistNode {// 分值double score;// 成员对象robj *obj;// 后退指针struct zskiplistNode *backward;// 层struct zskiplistLevel {// 前进指针struct zskiplistNode *forward;// 跨度unsigned int span;} level[]; } zskiplistNode;跳表的节点查找算法可以…